@@ -125,6 +125,91 @@ describe("ChartTooltipContent (recharts v3, #8610)", () => {
125125 expect ( chart . getByText ( "$120" ) ) . toBeTruthy ( ) ;
126126 } ) ;
127127
128+ // #10051: a numeric 0 is a real data point — the old `item.value &&` guard rendered it as a bare
129+ // React text child (losing tabular-nums / toLocaleString). Pin both arms of the nullish guard and
130+ // assert the digit sits inside the formatted span, not beside it.
131+ it ( "REGRESSION (#10051): zero value renders inside the tabular-nums span, not as a bare text child" , ( ) => {
132+ const zeroPayload = [
133+ {
134+ dataKey : "revenue" ,
135+ name : "revenue" ,
136+ value : 0 ,
137+ color : "#0ea5e9" ,
138+ payload : { month : "Jan" , revenue : 0 } ,
139+ } ,
140+ ] ;
141+ const chart = renderInChart (
142+ < ChartTooltipContent active payload = { zeroPayload } label = "Jan" /> ,
143+ ) ;
144+
145+ const valueSpan = chart . slot ( ) . querySelector ( "span.tabular-nums" ) ;
146+ expect ( valueSpan ) . not . toBeNull ( ) ;
147+ expect ( valueSpan ! . className ) . toContain ( "font-mono" ) ;
148+ expect ( valueSpan ! . className ) . toContain ( "tabular-nums" ) ;
149+ expect ( valueSpan ! . textContent ) . toBe ( "0" ) ;
150+
151+ // The formatted "0" must be a descendant of the span — not a direct text child of the row.
152+ const row = valueSpan ! . closest ( ".flex.w-full" ) ;
153+ expect ( row ) . not . toBeNull ( ) ;
154+ const directZero = Array . from ( row ! . childNodes ) . some (
155+ ( node ) => node . nodeType === Node . TEXT_NODE && node . textContent ?. trim ( ) === "0" ,
156+ ) ;
157+ expect ( directZero ) . toBe ( false ) ;
158+ expect ( chart . getByText ( "Revenue" ) ) . toBeTruthy ( ) ;
159+ } ) ;
160+
161+ it ( "omits the value span only when value is undefined or null (#10051)" , ( ) => {
162+ const undefinedPayload = [
163+ {
164+ dataKey : "revenue" ,
165+ name : "revenue" ,
166+ value : undefined ,
167+ color : "#0ea5e9" ,
168+ payload : { month : "Jan" , revenue : 0 } ,
169+ } ,
170+ ] ;
171+ const missing = renderInChart (
172+ < ChartTooltipContent active payload = { undefinedPayload } label = "Jan" /> ,
173+ ) ;
174+ expect ( missing . slot ( ) . textContent ) . toContain ( "Revenue" ) ;
175+ expect ( missing . slot ( ) . querySelector ( "span.tabular-nums" ) ) . toBeNull ( ) ;
176+ missing . unmount ( ) ;
177+
178+ const nullPayload = [
179+ {
180+ dataKey : "revenue" ,
181+ name : "revenue" ,
182+ value : null ,
183+ color : "#0ea5e9" ,
184+ payload : { month : "Jan" , revenue : 0 } ,
185+ } ,
186+ ] ;
187+ const nullish = renderInChart (
188+ < ChartTooltipContent active payload = { nullPayload as typeof payload } label = "Jan" /> ,
189+ ) ;
190+ expect ( nullish . slot ( ) . textContent ) . toContain ( "Revenue" ) ;
191+ expect ( nullish . slot ( ) . querySelector ( "span.tabular-nums" ) ) . toBeNull ( ) ;
192+ } ) ;
193+
194+ it ( "renders an empty-string value through the tabular-nums span (#10051)" , ( ) => {
195+ const emptyPayload = [
196+ {
197+ dataKey : "revenue" ,
198+ name : "revenue" ,
199+ value : "" ,
200+ color : "#0ea5e9" ,
201+ payload : { month : "Jan" , revenue : "" } ,
202+ } ,
203+ ] ;
204+ const chart = renderInChart (
205+ < ChartTooltipContent active payload = { emptyPayload } label = "Jan" /> ,
206+ ) ;
207+ const valueSpan = chart . slot ( ) . querySelector ( "span.tabular-nums" ) ;
208+ expect ( valueSpan ) . not . toBeNull ( ) ;
209+ expect ( valueSpan ! . textContent ) . toBe ( "" ) ;
210+ expect ( chart . getByText ( "Revenue" ) ) . toBeTruthy ( ) ;
211+ } ) ;
212+
128213 it ( "resolves a series by nameKey when the payload's own key is not the config key" , ( ) => {
129214 const chart = renderInChart (
130215 < ChartTooltipContent
0 commit comments