Compare commits

...

1 Commits

Author SHA1 Message Date
Abhi Kumar
316c5f5437 test(dashboards): clear the uPlot handle from the container it was created on
React detaches the container ref before effect cleanups run, so unmount and the empty-data
destroy left the handle on the detached node.
2026-10-27 13:46:29 +05:30
2 changed files with 58 additions and 2 deletions

View File

@@ -48,6 +48,9 @@ export default function UPlotChart({
const { setPlotContextInitialState } = usePlotContext();
const containerRef = useRef<HTMLDivElement>(null);
const plotInstanceRef = useRef<uPlot | null>(null);
// The container the live plot was created on. React detaches `containerRef`
// before effect cleanups run, so destroy clears this one, not the ref.
const plotHostRef = useRef<HTMLDivElement | null>(null);
const prevPropsRef = useRef<UPlotChartProps | null>(null);
/**
@@ -58,7 +61,8 @@ export default function UPlotChart({
onDestroy?.(plotInstanceRef.current);
plotInstanceRef.current.destroy();
plotInstanceRef.current = null;
setInstanceHandle(containerRef.current, null);
setInstanceHandle(plotHostRef.current, null);
plotHostRef.current = null;
setPlotContextInitialState({ uPlotInstance: null });
plotRef?.(null);
}
@@ -102,7 +106,8 @@ export default function UPlotChart({
});
plotInstanceRef.current = plot;
setInstanceHandle(containerRef.current, plot);
plotHostRef.current = containerRef.current;
setInstanceHandle(plotHostRef.current, plot);
}, [
config,
data,

View File

@@ -352,6 +352,57 @@ describe('UPlotChart', () => {
});
});
describe('instance handle', () => {
const hostOf = (call: number): HTMLElement & { __uplot?: unknown } =>
mockUPlotConstructor.mock.calls[call][2];
it('hangs the live instance on the container it was created on', () => {
render(
<UPlotChart
config={createMockConfig()}
data={validData}
width={600}
height={400}
/>,
{ wrapper: Wrapper },
);
expect(hostOf(0).__uplot).toBe(instances[0]);
});
it('clears the handle from that container on unmount', () => {
const { unmount } = render(
<UPlotChart
config={createMockConfig()}
data={validData}
width={600}
height={400}
/>,
{ wrapper: Wrapper },
);
const host = hostOf(0);
unmount();
expect(host.__uplot).toBeUndefined();
});
it('clears the handle from that container when the data becomes empty', () => {
const config = createMockConfig();
const { rerender } = render(
<UPlotChart config={config} data={validData} width={600} height={400} />,
{ wrapper: Wrapper },
);
const host = hostOf(0);
rerender(
<UPlotChart config={config} data={emptyData} width={600} height={400} />,
);
expect(host.__uplot).toBeUndefined();
});
});
describe('spanGaps data transformation', () => {
it('inserts null break points before passing data to uPlot when a gap exceeds the numeric threshold', () => {
const config = createMockConfig();