From c63267302d4f7db20178784779bf66ade89b25bb Mon Sep 17 00:00:00 2001 From: alex Date: Tue, 30 Jul 2024 17:42:45 +0200 Subject: [PATCH 1/8] [charts] Test pointer events --- .../src/BarChart/checkClickEvent.test.tsx | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 packages/x-charts/src/BarChart/checkClickEvent.test.tsx diff --git a/packages/x-charts/src/BarChart/checkClickEvent.test.tsx b/packages/x-charts/src/BarChart/checkClickEvent.test.tsx new file mode 100644 index 000000000000..4260d9d4507d --- /dev/null +++ b/packages/x-charts/src/BarChart/checkClickEvent.test.tsx @@ -0,0 +1,106 @@ +import * as React from 'react'; +import { expect } from 'chai'; +import { createRenderer, fireEvent } from '@mui/internal-test-utils'; +import { spy } from 'sinon'; +import { BarChart } from '@mui/x-charts/BarChart'; + +function firePointerEvent( + target: Element, + type: 'pointerstart' | 'pointermove' | 'pointerend', + options: Pick, +): void { + const originalGetBoundingClientRect = target.getBoundingClientRect; + target.getBoundingClientRect = () => ({ + x: 0, + y: 0, + bottom: 0, + height: 400, + left: 0, + right: 0, + top: 0, + width: 400, + toJSON() { + return { + x: 0, + y: 0, + bottom: 0, + height: 400, + left: 0, + right: 0, + top: 0, + width: 400, + }; + }, + }); + const event = new window.PointerEvent(type, { + bubbles: true, + cancelable: true, + composed: true, + isPrimary: true, + ...options, + }); + + fireEvent(target, event); + target.getBoundingClientRect = originalGetBoundingClientRect; +} + +const config = { + dataset: [ + { x: 'A', v1: 4, v2: 2 }, + { x: 'B', v1: 1, v2: 1 }, + ], + margin: { top: 0, left: 0, bottom: 0, right: 0 }, + width: 400, + height: 400, +}; + +// Plot as follow to simplify click position +// +// | X +// | X +// | X X +// | X X X X +// ---A---B- + +describe('BarChart - click event', () => { + const { render } = createRenderer(); + + it('should provide the accurate context as second argument', function test() { + if (/jsdom/.test(window.navigator.userAgent)) { + // can't do Pointer event with JSDom https://github.com/jsdom/jsdom/issues/2527 + this.skip(); + } + const onAxisClick = spy(); + render( +
+ +
, + ); + const svg = document.querySelector('svg')!; + + firePointerEvent(svg, 'pointermove', { + clientX: 201, + clientY: 60, + }); + fireEvent.click(svg); + + expect(onAxisClick.lastCall.args[1]).to.deep.equal({ + dataIndex: 0, + axisValue: 'A', + seriesValues: { s1: 4, s2: 2 }, + }); + }); +}); From bea8ef630019ffc59fd81dfd444bbdb651a188c0 Mon Sep 17 00:00:00 2001 From: alex Date: Thu, 8 Aug 2024 16:14:16 +0200 Subject: [PATCH 2/8] add tests --- .../src/BarChart/checkClickEvent.test.tsx | 150 ++++++++++++++---- 1 file changed, 119 insertions(+), 31 deletions(-) diff --git a/packages/x-charts/src/BarChart/checkClickEvent.test.tsx b/packages/x-charts/src/BarChart/checkClickEvent.test.tsx index 4260d9d4507d..d3b2f8cf3d32 100644 --- a/packages/x-charts/src/BarChart/checkClickEvent.test.tsx +++ b/packages/x-charts/src/BarChart/checkClickEvent.test.tsx @@ -14,21 +14,21 @@ function firePointerEvent( x: 0, y: 0, bottom: 0, - height: 400, + height: 0, left: 0, right: 0, top: 0, - width: 400, + width: 0, toJSON() { return { x: 0, y: 0, bottom: 0, - height: 400, + height: 0, left: 0, right: 0, top: 0, - width: 400, + width: 0, }; }, }); @@ -62,22 +62,68 @@ const config = { // | X X X X // ---A---B- +const isJSDOM = /jsdom/.test(window.navigator.userAgent); + describe('BarChart - click event', () => { const { render } = createRenderer(); - it('should provide the accurate context as second argument', function test() { - if (/jsdom/.test(window.navigator.userAgent)) { - // can't do Pointer event with JSDom https://github.com/jsdom/jsdom/issues/2527 - this.skip(); - } - const onAxisClick = spy(); - render( -
+ describe('onAxisClick', () => { + it('should provide the accurate context as second argument', function test() { + if (isJSDOM) { + // can't do Pointer event with JSDom https://github.com/jsdom/jsdom/issues/2527 + this.skip(); + } + const onAxisClick = spy(); + render( +
+ +
, + ); + const svg = document.querySelector('svg')!; + + firePointerEvent(svg, 'pointermove', { + clientX: 198, + clientY: 60, + }); + fireEvent.click(svg); + + expect(onAxisClick.lastCall.args[1]).to.deep.equal({ + dataIndex: 0, + axisValue: 'A', + seriesValues: { s1: 4, s2: 2 }, + }); + + firePointerEvent(svg, 'pointermove', { + clientX: 201, + clientY: 60, + }); + fireEvent.click(svg); + + expect(onAxisClick.lastCall.args[1]).to.deep.equal({ + dataIndex: 1, + axisValue: 'B', + seriesValues: { s1: 1, s2: 1 }, + }); + }); + }); + + describe('onItemClick', () => { + it('should add cursor="pointer" to bar elements', function test() { + render( { { dataKey: 'v2', id: 's2' }, ]} xAxis={[{ scaleType: 'band', dataKey: 'x' }]} - onAxisClick={onAxisClick} - /> -
, - ); - const svg = document.querySelector('svg')!; - - firePointerEvent(svg, 'pointermove', { - clientX: 201, - clientY: 60, + onItemClick={() => {}} + />, + ); + const rectangles = document.querySelectorAll('rect.MuiBarElement-root'); + + expect( + Array.from(rectangles).map((rectangle) => rectangle.getAttribute('cursor')), + ).to.deep.equal(['pointer', 'pointer', 'pointer', 'pointer']); }); - fireEvent.click(svg); - expect(onAxisClick.lastCall.args[1]).to.deep.equal({ - dataIndex: 0, - axisValue: 'A', - seriesValues: { s1: 4, s2: 2 }, + it('should provide the accurate context as second argument', function test() { + if (isJSDOM) { + // can't do Pointer event with JSDom https://github.com/jsdom/jsdom/issues/2527 + this.skip(); + } + const onItemClick = spy(); + render( +
+ +
, + ); + + const rectangles = document.querySelectorAll('rect.MuiBarElement-root'); + + fireEvent.click(rectangles[0]); + expect(onItemClick.lastCall.args[1]).to.deep.equal({ + type: 'bar', + seriesId: 's1', + dataIndex: 0, + }); + + fireEvent.click(rectangles[1]); + expect(onItemClick.lastCall.args[1]).to.deep.equal({ + type: 'bar', + seriesId: 's1', + dataIndex: 1, + }); + + fireEvent.click(rectangles[2]); + expect(onItemClick.lastCall.args[1]).to.deep.equal({ + type: 'bar', + seriesId: 's2', + dataIndex: 0, + }); }); }); }); From 911ee49ac8badae8076d705f48b764f950af6e7d Mon Sep 17 00:00:00 2001 From: alex Date: Thu, 8 Aug 2024 16:20:49 +0200 Subject: [PATCH 3/8] flavien feedback --- packages/x-charts/src/BarChart/checkClickEvent.test.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/x-charts/src/BarChart/checkClickEvent.test.tsx b/packages/x-charts/src/BarChart/checkClickEvent.test.tsx index d3b2f8cf3d32..46035f36cf48 100644 --- a/packages/x-charts/src/BarChart/checkClickEvent.test.tsx +++ b/packages/x-charts/src/BarChart/checkClickEvent.test.tsx @@ -68,7 +68,7 @@ describe('BarChart - click event', () => { const { render } = createRenderer(); describe('onAxisClick', () => { - it('should provide the accurate context as second argument', function test() { + it('should provide the right context as second argument', function test() { if (isJSDOM) { // can't do Pointer event with JSDom https://github.com/jsdom/jsdom/issues/2527 this.skip(); @@ -141,7 +141,7 @@ describe('BarChart - click event', () => { ).to.deep.equal(['pointer', 'pointer', 'pointer', 'pointer']); }); - it('should provide the accurate context as second argument', function test() { + it('should provide the right context as second argument', function test() { if (isJSDOM) { // can't do Pointer event with JSDom https://github.com/jsdom/jsdom/issues/2527 this.skip(); From 7828ec7777b4f34e98872ce308ed611635c4676f Mon Sep 17 00:00:00 2001 From: alex Date: Fri, 9 Aug 2024 16:18:44 +0200 Subject: [PATCH 4/8] Extends test to other charts --- .../src/BarChart/checkClickEvent.test.tsx | 43 +-- .../src/LineChart/checkClickEvent.test.tsx | 282 ++++++++++++++++++ .../src/ScatterChart/checkClickEvent.test.tsx | 168 +++++++++++ .../x-charts/src/tests/firePointerEvent.ts | 41 +++ 4 files changed, 493 insertions(+), 41 deletions(-) create mode 100644 packages/x-charts/src/LineChart/checkClickEvent.test.tsx create mode 100644 packages/x-charts/src/ScatterChart/checkClickEvent.test.tsx create mode 100644 packages/x-charts/src/tests/firePointerEvent.ts diff --git a/packages/x-charts/src/BarChart/checkClickEvent.test.tsx b/packages/x-charts/src/BarChart/checkClickEvent.test.tsx index 46035f36cf48..7804217e7402 100644 --- a/packages/x-charts/src/BarChart/checkClickEvent.test.tsx +++ b/packages/x-charts/src/BarChart/checkClickEvent.test.tsx @@ -3,46 +3,7 @@ import { expect } from 'chai'; import { createRenderer, fireEvent } from '@mui/internal-test-utils'; import { spy } from 'sinon'; import { BarChart } from '@mui/x-charts/BarChart'; - -function firePointerEvent( - target: Element, - type: 'pointerstart' | 'pointermove' | 'pointerend', - options: Pick, -): void { - const originalGetBoundingClientRect = target.getBoundingClientRect; - target.getBoundingClientRect = () => ({ - x: 0, - y: 0, - bottom: 0, - height: 0, - left: 0, - right: 0, - top: 0, - width: 0, - toJSON() { - return { - x: 0, - y: 0, - bottom: 0, - height: 0, - left: 0, - right: 0, - top: 0, - width: 0, - }; - }, - }); - const event = new window.PointerEvent(type, { - bubbles: true, - cancelable: true, - composed: true, - isPrimary: true, - ...options, - }); - - fireEvent(target, event); - target.getBoundingClientRect = originalGetBoundingClientRect; -} +import { firePointerEvent } from '../tests/firePointerEvent'; const config = { dataset: [ @@ -77,7 +38,7 @@ describe('BarChart - click event', () => { render(
{ + const { render } = createRenderer(); + + describe('onAxisClick', () => { + it('should provide the right context as second argument', function test() { + if (isJSDOM) { + // can't do Pointer event with JSDom https://github.com/jsdom/jsdom/issues/2527 + this.skip(); + } + const onAxisClick = spy(); + render( +
+ +
, + ); + const svg = document.querySelector('svg')!; + + firePointerEvent(svg, 'pointermove', { + clientX: 198, + clientY: 60, + }); + fireEvent.click(svg); + + expect(onAxisClick.lastCall.args[1]).to.deep.equal({ + dataIndex: 1, + axisValue: 20, + seriesValues: { s1: 5, s2: 8 }, + }); + + firePointerEvent(svg, 'pointermove', { + clientX: 201, + clientY: 60, + }); + fireEvent.click(svg); + + expect(onAxisClick.lastCall.args[1]).to.deep.equal({ + dataIndex: 2, + axisValue: 30, + seriesValues: { s1: 8, s2: 5 }, + }); + }); + }); + + describe('onMarkClick', () => { + it('should add cursor="pointer" to bar elements', function test() { + render( + {}} + />, + ); + const marks = document.querySelectorAll('path.MuiMarkElement-root'); + + expect(Array.from(marks).map((mark) => mark.getAttribute('cursor'))).to.deep.equal([ + 'pointer', + 'pointer', + 'pointer', + 'pointer', + 'pointer', + 'pointer', + 'pointer', + 'pointer', + ]); + }); + + it('should provide the right context as second argument', function test() { + if (isJSDOM) { + // can't do Pointer event with JSDom https://github.com/jsdom/jsdom/issues/2527 + this.skip(); + } + const onMarkClick = spy(); + render( +
+ +
, + ); + + const marks = document.querySelectorAll('path.MuiMarkElement-root'); + + fireEvent.click(marks[0]); + expect(onMarkClick.lastCall.args[1]).to.deep.equal({ + type: 'line', + seriesId: 's1', + dataIndex: 0, + }); + + fireEvent.click(marks[1]); + expect(onMarkClick.lastCall.args[1]).to.deep.equal({ + type: 'line', + seriesId: 's1', + dataIndex: 1, + }); + + fireEvent.click(marks[4]); + expect(onMarkClick.lastCall.args[1]).to.deep.equal({ + type: 'line', + seriesId: 's2', + dataIndex: 0, + }); + }); + }); + + describe('onAreaClick', () => { + it('should add cursor="pointer" to bar elements', function test() { + render( + {}} + />, + ); + const areas = document.querySelectorAll('path.MuiAreaElement-root'); + + expect(Array.from(areas).map((area) => area.getAttribute('cursor'))).to.deep.equal([ + 'pointer', + 'pointer', + ]); + }); + + it('should provide the right context as second argument', function test() { + if (isJSDOM) { + // can't do Pointer event with JSDom https://github.com/jsdom/jsdom/issues/2527 + this.skip(); + } + const onAreaClick = spy(); + render( +
+ +
, + ); + + const areas = document.querySelectorAll('path.MuiAreaElement-root'); + + fireEvent.click(areas[0]); + expect(onAreaClick.lastCall.args[1]).to.deep.equal({ + type: 'line', + seriesId: 's1', + }); + + fireEvent.click(areas[1]); + expect(onAreaClick.lastCall.args[1]).to.deep.equal({ + type: 'line', + seriesId: 's2', + }); + }); + }); + + describe('onLineClick', () => { + it('should add cursor="pointer" to bar elements', function test() { + render( + {}} + />, + ); + const lines = document.querySelectorAll('path.MuiLineElement-root'); + + expect(Array.from(lines).map((line) => line.getAttribute('cursor'))).to.deep.equal([ + 'pointer', + 'pointer', + ]); + }); + + it('should provide the right context as second argument', function test() { + if (isJSDOM) { + // can't do Pointer event with JSDom https://github.com/jsdom/jsdom/issues/2527 + this.skip(); + } + const onLineClick = spy(); + render( +
+ +
, + ); + + const lines = document.querySelectorAll('path.MuiLineElement-root'); + + fireEvent.click(lines[0]); + expect(onLineClick.lastCall.args[1]).to.deep.equal({ + type: 'line', + seriesId: 's1', + }); + + fireEvent.click(lines[1]); + expect(onLineClick.lastCall.args[1]).to.deep.equal({ + type: 'line', + seriesId: 's2', + }); + }); + }); +}); diff --git a/packages/x-charts/src/ScatterChart/checkClickEvent.test.tsx b/packages/x-charts/src/ScatterChart/checkClickEvent.test.tsx new file mode 100644 index 000000000000..1838fa54c27a --- /dev/null +++ b/packages/x-charts/src/ScatterChart/checkClickEvent.test.tsx @@ -0,0 +1,168 @@ +import * as React from 'react'; +import { expect } from 'chai'; +import { createRenderer, fireEvent } from '@mui/internal-test-utils'; +import { spy } from 'sinon'; +import { ScatterChart } from '@mui/x-charts/ScatterChart'; + +const config = { + dataset: [ + { id: 1, x: 0, y: 10 }, + { id: 2, x: 10, y: 10 }, + { id: 3, x: 10, y: 0 }, + { id: 4, x: 0, y: 0 }, + { id: 5, x: 5, y: 5 }, + ], + margin: { top: 0, left: 0, bottom: 0, right: 0 }, + width: 100, + height: 100, +}; + +// Plot on series as a dice 5 +// +// 1...2 +// ..... +// ..5.. +// ..... +// 4...3 + +describe('ScatterChart - click event', () => { + const { render } = createRenderer(); + + describe('onItemClick - using vornoid', () => { + it('should provide the right context as second argument when clicking svg', function test() { + const onItemClick = spy(); + render( +
+ +
, + ); + const svg = document.querySelector('svg')!; + + fireEvent.click(svg, { + clientX: 10, + clientY: 10, + }); + expect(onItemClick.lastCall.args[1]).to.deep.equal({ + type: 'scatter', + dataIndex: 0, + seriesId: 's1', + }); + + fireEvent.click(svg, { + clientX: 30, + clientY: 30, + }); + expect(onItemClick.lastCall.args[1]).to.deep.equal({ + type: 'scatter', + dataIndex: 4, + seriesId: 's1', + }); + + expect(onItemClick.callCount).to.equal(2); + }); + + it('should provide the right context as second argument when clicking mark', function test() { + const onItemClick = spy(); + render( +
+ +
, + ); + const marks = document.querySelectorAll('circle'); + + fireEvent.click(marks[1], { + clientX: 99, + clientY: 2, + }); + + expect(onItemClick.lastCall.args[1]).to.deep.equal({ + type: 'scatter', + dataIndex: 1, + seriesId: 's1', + }); + expect(onItemClick.callCount).to.equal(1); // Make sure voronoid + item click does not duplicate event triggering + }); + }); + + describe('onItemClick - disabling vornoid', () => { + it('should not call onItemClick when clicking the SVG', function test() { + const onItemClick = spy(); + render( +
+ +
, + ); + const svg = document.querySelector('svg')!; + + fireEvent.click(svg, { + clientX: 10, + clientY: 10, + }); + expect(onItemClick.callCount).to.equal(0); + }); + + it('should provide the right context as second argument when clicking mark', function test() { + const onItemClick = spy(); + render( +
+ +
, + ); + const marks = document.querySelectorAll('circle'); + + fireEvent.click(marks[1], { + clientX: 99, + clientY: 2, + }); + + expect(onItemClick.lastCall.args[1]).to.deep.equal({ + type: 'scatter', + dataIndex: 1, + seriesId: 's1', + }); + expect(onItemClick.callCount).to.equal(1); // Make sure voronoid + item click does not duplicate event triggering + }); + }); +}); diff --git a/packages/x-charts/src/tests/firePointerEvent.ts b/packages/x-charts/src/tests/firePointerEvent.ts new file mode 100644 index 000000000000..ae639a28fcfc --- /dev/null +++ b/packages/x-charts/src/tests/firePointerEvent.ts @@ -0,0 +1,41 @@ +import { fireEvent } from '@mui/internal-test-utils'; + +export function firePointerEvent( + target: Element, + type: 'pointerstart' | 'pointermove' | 'pointerend', + options: Pick, +): void { + const originalGetBoundingClientRect = target.getBoundingClientRect; + target.getBoundingClientRect = () => ({ + x: 0, + y: 0, + bottom: 0, + height: 0, + left: 0, + right: 0, + top: 0, + width: 0, + toJSON() { + return { + x: 0, + y: 0, + bottom: 0, + height: 0, + left: 0, + right: 0, + top: 0, + width: 0, + }; + }, + }); + const event = new window.PointerEvent(type, { + bubbles: true, + cancelable: true, + composed: true, + isPrimary: true, + ...options, + }); + + fireEvent(target, event); + target.getBoundingClientRect = originalGetBoundingClientRect; +} From a00a0f1f8385cd49b3bdf36cc5095913b64008ec Mon Sep 17 00:00:00 2001 From: alex Date: Tue, 13 Aug 2024 11:02:24 +0200 Subject: [PATCH 5/8] add pie chart --- .../src/PieChart/checkClickEvent.test.tsx | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 packages/x-charts/src/PieChart/checkClickEvent.test.tsx diff --git a/packages/x-charts/src/PieChart/checkClickEvent.test.tsx b/packages/x-charts/src/PieChart/checkClickEvent.test.tsx new file mode 100644 index 000000000000..bc5f72d36874 --- /dev/null +++ b/packages/x-charts/src/PieChart/checkClickEvent.test.tsx @@ -0,0 +1,74 @@ +import * as React from 'react'; +import { expect } from 'chai'; +import { createRenderer, fireEvent } from '@mui/internal-test-utils'; +import { spy } from 'sinon'; +import { PieChart } from '@mui/x-charts/PieChart'; + +const config = { + width: 400, + height: 400, +}; + +describe('PieChart - click event', () => { + const { render } = createRenderer(); + + describe('onItemClick', () => { + it('should add cursor="pointer" to bar elements', function test() { + render( + {}} + />, + ); + const slices = document.querySelectorAll('path.MuiPieArc-root'); + + expect(Array.from(slices).map((slice) => slice.getAttribute('cursor'))).to.deep.equal([ + 'pointer', + 'pointer', + ]); + }); + + it('should provide the right context as second argument', function test() { + const onItemClick = spy(); + render( + , + ); + const slices = document.querySelectorAll('path.MuiPieArc-root'); + + fireEvent.click(slices[0]); + expect(onItemClick.lastCall.args[1]).to.deep.equal({ + type: 'pie', + seriesId: 's1', + dataIndex: 0, + }); + + fireEvent.click(slices[1]); + expect(onItemClick.lastCall.args[1]).to.deep.equal({ + type: 'pie', + seriesId: 's1', + dataIndex: 1, + }); + }); + }); +}); From 2b4b048718c00e02cf3e538b258243a5d47a48c9 Mon Sep 17 00:00:00 2001 From: alex Date: Tue, 13 Aug 2024 11:56:46 +0200 Subject: [PATCH 6/8] fix --- .../src/ScatterChart/checkClickEvent.test.tsx | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/packages/x-charts/src/ScatterChart/checkClickEvent.test.tsx b/packages/x-charts/src/ScatterChart/checkClickEvent.test.tsx index 1838fa54c27a..08b8148eff60 100644 --- a/packages/x-charts/src/ScatterChart/checkClickEvent.test.tsx +++ b/packages/x-charts/src/ScatterChart/checkClickEvent.test.tsx @@ -25,11 +25,17 @@ const config = { // ..... // 4...3 +const isJSDOM = /jsdom/.test(window.navigator.userAgent); + describe('ScatterChart - click event', () => { const { render } = createRenderer(); describe('onItemClick - using vornoid', () => { it('should provide the right context as second argument when clicking svg', function test() { + if (isJSDOM) { + // svg.createSVGPoint not supported by JSDom https://github.com/jsdom/jsdom/issues/300 + this.skip(); + } const onItemClick = spy(); render(
{ }); it('should provide the right context as second argument when clicking mark', function test() { + if (isJSDOM) { + this.skip(); + } const onItemClick = spy(); render(
{ describe('onItemClick - disabling vornoid', () => { it('should not call onItemClick when clicking the SVG', function test() { + if (isJSDOM) { + this.skip(); + } const onItemClick = spy(); render(
{ }); it('should provide the right context as second argument when clicking mark', function test() { + if (isJSDOM) { + this.skip(); + } const onItemClick = spy(); render(
Date: Tue, 13 Aug 2024 14:13:01 +0200 Subject: [PATCH 7/8] clean DOM after testing --- packages/x-charts/src/internals/domUtils.ts | 8 +++++++- packages/x-charts/src/internals/index.ts | 1 + test/utils/mochaHooks.js | 2 ++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/x-charts/src/internals/domUtils.ts b/packages/x-charts/src/internals/domUtils.ts index d7aca59b459f..1b4a906460c8 100644 --- a/packages/x-charts/src/internals/domUtils.ts +++ b/packages/x-charts/src/internals/domUtils.ts @@ -45,7 +45,7 @@ const STYLE_LIST = [ 'marginTop', 'marginBottom', ]; -const MEASUREMENT_SPAN_ID = 'mui_measurement_span'; +export const MEASUREMENT_SPAN_ID = 'mui_measurement_span'; /** * @@ -152,3 +152,9 @@ export const getStringSize = (text: string | number, style: React.CSSProperties return { width: 0, height: 0 }; } }; + +// eslint-disable-next-line @typescript-eslint/naming-convention +export function unstable_cleanupDOM() { + const measurementSpan = document.getElementById(MEASUREMENT_SPAN_ID); + measurementSpan?.remove(); +} diff --git a/packages/x-charts/src/internals/index.ts b/packages/x-charts/src/internals/index.ts index f4020f5d0918..d5f2c926fb26 100644 --- a/packages/x-charts/src/internals/index.ts +++ b/packages/x-charts/src/internals/index.ts @@ -21,6 +21,7 @@ export * from './configInit'; export * from './getLabel'; export * from './getSVGPoint'; export * from './isDefined'; +export { unstable_cleanupDOM } from './domUtils'; // contexts diff --git a/test/utils/mochaHooks.js b/test/utils/mochaHooks.js index b5f113969c06..5e774ee1be5c 100644 --- a/test/utils/mochaHooks.js +++ b/test/utils/mochaHooks.js @@ -2,6 +2,7 @@ import sinon from 'sinon'; import { unstable_resetCleanupTracking as unstable_resetCleanupTrackingDataGrid } from '@mui/x-data-grid'; import { unstable_resetCleanupTracking as unstable_resetCleanupTrackingDataGridPro } from '@mui/x-data-grid-pro'; import { unstable_resetCleanupTracking as unstable_resetCleanupTrackingTreeView } from '@mui/x-tree-view'; +import { unstable_cleanupDOM as unstable_cleanupDOMCharts } from '@mui/x-charts/internals'; import { clearWarningsCache } from '@mui/x-data-grid/internals'; import { generateTestLicenseKey, setupTestLicenseKey } from './testLicense'; @@ -27,6 +28,7 @@ export function createXMochaHooks(coreMochaHooks = {}) { unstable_resetCleanupTrackingDataGrid(); unstable_resetCleanupTrackingDataGridPro(); unstable_resetCleanupTrackingTreeView(); + unstable_cleanupDOMCharts(); // Restore Sinon default sandbox to avoid memory leak // See https://github.com/sinonjs/sinon/issues/1866 From c0987f25c56666c7e8baa9d62f72ec4834295622 Mon Sep 17 00:00:00 2001 From: alex Date: Tue, 13 Aug 2024 15:07:48 +0200 Subject: [PATCH 8/8] test --- packages/x-charts/src/internals/domUtils.ts | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/x-charts/src/internals/domUtils.ts b/packages/x-charts/src/internals/domUtils.ts index 1b4a906460c8..e8a1b2e2d119 100644 --- a/packages/x-charts/src/internals/domUtils.ts +++ b/packages/x-charts/src/internals/domUtils.ts @@ -97,6 +97,7 @@ export const getStyleString = (style: React.CSSProperties) => '', ); +let domCleanTimeout: NodeJS.Timeout | undefined; /** * * @param text The string to estimate @@ -134,7 +135,6 @@ export const getStringSize = (text: string | number, style: React.CSSProperties return styleKey; }); measurementSpan.textContent = str; - const rect = measurementSpan.getBoundingClientRect(); const result = { width: rect.width, height: rect.height }; @@ -147,6 +147,14 @@ export const getStringSize = (text: string | number, style: React.CSSProperties stringCache.cacheCount += 1; } + if (domCleanTimeout) { + clearTimeout(domCleanTimeout); + } + domCleanTimeout = setTimeout(() => { + // Limit node cleaning to once per render cycle + measurementSpan.textContent = ''; + }, 0); + return result; } catch (e) { return { width: 0, height: 0 }; @@ -155,6 +163,6 @@ export const getStringSize = (text: string | number, style: React.CSSProperties // eslint-disable-next-line @typescript-eslint/naming-convention export function unstable_cleanupDOM() { - const measurementSpan = document.getElementById(MEASUREMENT_SPAN_ID); - measurementSpan?.remove(); + // const measurementSpan = document.getElementById(MEASUREMENT_SPAN_ID); + // measurementSpan?.remove(); }