Fix/per graphical item formatter prop#7287
Conversation
…charts#6210) Re-adds the ability to pass a `formatter` prop directly to graphical chart components (Line, Bar, Area, Scatter, Funnel, Pie, RadialBar) to format tooltip values per series. This was available in v2 but was silently dropped when Redux-based tooltip state was introduced in v3. The per-item formatter takes precedence over the Tooltip-level formatter, preserving the existing `entry.formatter || formatter || defaultFormatter` chain in DefaultTooltipContent.
- Update readProject inline snapshots to include new `formatter` prop on Bar - Add commentSimilarityExceptions entry for Label/LabelList `formatter`, which serializes SVG text (distinct from graphical item tooltip formatters)
WalkthroughThe PR adds an optional Changes
Sequence DiagramsequenceDiagram
participant Component as Chart Component<br/>(Area, Bar, etc.)
participant Settings as Tooltip Settings<br/>Builder
participant Payload as Tooltip Payload<br/>Configuration
participant Tooltip as DefaultTooltipContent
Component->>Settings: Pass formatter prop to<br/>SetComponentTooltipEntrySettings()
Settings->>Payload: Store formatter in<br/>TooltipPayloadConfiguration.settings
Tooltip->>Payload: Read formatter from<br/>entry.settings.formatter
Tooltip->>Tooltip: Apply formatter if present<br/>(precedence over Tooltip.formatter)
Tooltip-->>Component: Render formatted value
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Review rate limit: 7/8 reviews remaining, refill in 7 minutes and 30 seconds.Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (3)
src/polar/Pie.tsx (1)
356-360: 🏗️ Heavy liftAdd direct tests for Pie/Funnel/Scatter/RadialBar formatter paths
The formatter wiring is added across multiple components, but the current test coverage described in this PR validates only Bar/Line behavior. Please add component-level assertions (or a shared parametrized suite) for Pie/Funnel/Scatter/RadialBar tooltip payload + rendered value paths to prevent regressions in component-specific payload shapes.
As per coding guidelines
src/**/*.{ts,tsx}: Aim for 100% unit test code coverage when writing new code.Also applies to: 424-487, 1012-1025
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/polar/Pie.tsx` around lines 356 - 360, Add unit tests that cover the tooltip formatter wiring for Pie, Funnel, Scatter and RadialBar components: for each component (Pie component's formatter prop, Funnel, Scatter, RadialBar) write tests that render the component with a mock Tooltip.formatter function and assert both the payload shape passed into the formatter and the final rendered tooltip value; you can implement a shared parametrized test suite that iterates over component constructors/names and checks (1) that the formatter is called with the expected payload shape and fields, and (2) that the formatted string is rendered in the Tooltip output, targeting the Tooltip component’s formatter prop used by each component to prevent regressions in component-specific payload shapes.test/component/Tooltip/graphicalItem.formatter.spec.tsx (2)
34-42: ⚡ Quick winAssert selector call counts for
createSelectorTestCasespy.Please add
spycall-count checks in selector-based tests to catch accidental extra rerenders in tooltip state selection.Based on learnings: "Applies to test/**/*.{test,spec}.{ts,tsx} : Verify the number of selector calls using the spy object from
createSelectorTestCaseto spot unnecessary re-renders and improve performance."Also applies to: 95-101, 117-125
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@test/component/Tooltip/graphicalItem.formatter.spec.tsx` around lines 34 - 42, Add assertions that verify the spy returned from createSelectorTestCase (the spy variable used in the selector-based tests) was called the expected number of times to catch extra selector invocations; for example, after rendering in the test that calls renderTestCase(state => selectTooltipPayload(...)) add an assertion like expect(spy).toHaveBeenCalledTimes(1) (or the correct expected count) immediately before or after the existing expectLastCalledWith check, and apply the same pattern to the other selector-based tests that use the spy so each test asserts the spy call count.
16-134: ⚡ Quick winAdd at least one
Areaformatter test in this suite.This suite validates Bar/Line well, but the PR also wires
formatterintoArea; adding one payload+render assertion forAreawould close the regression gap on changed source behavior.As per coding guidelines "
src/**/*.{ts,tsx}: Aim for 100% unit test code coverage when writing new code."🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@test/component/Tooltip/graphicalItem.formatter.spec.tsx` around lines 16 - 134, Add a new test block mirroring the existing "Line with formatter" or "Bar with formatter" cases but using Area/AreaChart: create an areaFormatter vi.fn(() => 'AREA_FORMATTED'), render via createSelectorTestCase with <AreaChart ...><Tooltip /><Area dataKey="pv" id="area-pv" formatter={areaFormatter} /></AreaChart>, then (1) assert selectTooltipPayload(state, 'axis', 'hover', '1') contains an entry with dataKey: 'pv' and formatter: areaFormatter and (2) render and use showTooltip with areaChartMouseHoverTooltipSelector and expectTooltipPayload to show 'pv : AREA_FORMATTED'; reference Area, AreaChart, areaFormatter, selectTooltipPayload, createSelectorTestCase, showTooltip, expectTooltipPayload.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@src/polar/Pie.tsx`:
- Around line 356-360: Add unit tests that cover the tooltip formatter wiring
for Pie, Funnel, Scatter and RadialBar components: for each component (Pie
component's formatter prop, Funnel, Scatter, RadialBar) write tests that render
the component with a mock Tooltip.formatter function and assert both the payload
shape passed into the formatter and the final rendered tooltip value; you can
implement a shared parametrized test suite that iterates over component
constructors/names and checks (1) that the formatter is called with the expected
payload shape and fields, and (2) that the formatted string is rendered in the
Tooltip output, targeting the Tooltip component’s formatter prop used by each
component to prevent regressions in component-specific payload shapes.
In `@test/component/Tooltip/graphicalItem.formatter.spec.tsx`:
- Around line 34-42: Add assertions that verify the spy returned from
createSelectorTestCase (the spy variable used in the selector-based tests) was
called the expected number of times to catch extra selector invocations; for
example, after rendering in the test that calls renderTestCase(state =>
selectTooltipPayload(...)) add an assertion like
expect(spy).toHaveBeenCalledTimes(1) (or the correct expected count) immediately
before or after the existing expectLastCalledWith check, and apply the same
pattern to the other selector-based tests that use the spy so each test asserts
the spy call count.
- Around line 16-134: Add a new test block mirroring the existing "Line with
formatter" or "Bar with formatter" cases but using Area/AreaChart: create an
areaFormatter vi.fn(() => 'AREA_FORMATTED'), render via createSelectorTestCase
with <AreaChart ...><Tooltip /><Area dataKey="pv" id="area-pv"
formatter={areaFormatter} /></AreaChart>, then (1) assert
selectTooltipPayload(state, 'axis', 'hover', '1') contains an entry with
dataKey: 'pv' and formatter: areaFormatter and (2) render and use showTooltip
with areaChartMouseHoverTooltipSelector and expectTooltipPayload to show 'pv :
AREA_FORMATTED'; reference Area, AreaChart, areaFormatter, selectTooltipPayload,
createSelectorTestCase, showTooltip, expectTooltipPayload.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: c4aaa59b-3191-48eb-9688-bc8f838477f5
📒 Files selected for processing (10)
omnidoc/commentSimilarityExceptions.tsomnidoc/readProject.spec.tssrc/cartesian/Area.tsxsrc/cartesian/Bar.tsxsrc/cartesian/Funnel.tsxsrc/cartesian/Line.tsxsrc/cartesian/Scatter.tsxsrc/polar/Pie.tsxsrc/polar/RadialBar.tsxtest/component/Tooltip/graphicalItem.formatter.spec.tsx
Bundle ReportChanges will increase total bundle size by 1.68kB (0.03%) ⬆️. This is within the configured threshold ✅ Detailed changes
Affected Assets, Files, and Routes:view changes for bundle: recharts/bundle-umdAssets Changed:
view changes for bundle: recharts/bundle-treeshaking-polarAssets Changed:
view changes for bundle: recharts/bundle-cjsAssets Changed:
view changes for bundle: recharts/bundle-es6Assets Changed:
view changes for bundle: recharts/bundle-treeshaking-cartesianAssets Changed:
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #7287 +/- ##
=======================================
Coverage 89.05% 89.05%
=======================================
Files 541 541
Lines 41088 41109 +21
Branches 5563 5564 +1
=======================================
+ Hits 36589 36610 +21
Misses 4491 4491
Partials 8 8 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
@ckifer Would you mind taking a loot at this PR please? Thanks in advance! |
ckifer
left a comment
There was a problem hiding this comment.
It looks ok to me at a glance, can you add tests for more than just bar please? You should be able to do the same tests in an it.each
cc @PavelVanecek to review before merging as well. I'm just looking from my phone which isn't a great place to review PRs 😅
Happy to! |
| components: ['Label', 'LabelList'], | ||
| props: ['formatter'], | ||
| reason: | ||
| 'Label and LabelList formatter serializes content for SVG text rendering, unlike graphical item formatters which format tooltip values', |
There was a problem hiding this comment.
Does it really? Or is this hallucination?
There was a problem hiding this comment.
The reason string is accurate in intent but "serializes" is slightly imprecise — it really just transforms the value.
The Label/LabelList formatter has the signature:
type LabelFormatter = (label: RenderableText) => RenderableText;It takes a raw value and returns something renderable inside an SVG element — typically a formatted string like 4000 → "4.0k". It never touches the tooltip.
The Bar/Line formatter on the other hand has a much richer signature:
(value, name, entry, index, payload) => ReactNodeand formats values shown in the HTML tooltip overlay.
Same prop name, completely different context and signature — hence the exception. Happy to update the wording to may be "transforms the label value for SVG text display" if that reads clearer.
There was a problem hiding this comment.
@PavelVanecek Just bumping this up incase if you have missed it!
Description
Restores the ability to pass a
formatterprop directly to graphical chart components (Line,Bar,Area,Scatter,Funnel,Pie,RadialBar) to format tooltip values on a per-series basis.Each component now accepts a
formatterprop of typeFormatter. When set, it takes precedence over theformatterprop defined on the
<Tooltip>component, following the existingentry.formatter || formatter || defaultFormatterchain already present in
DefaultTooltipContent.Related Issue
Fixes #6210
Motivation and Context
In v2, users could co-locate tooltip formatting logic with each graphical item, which was ergonomic when charts had
multiple series each requiring different formatting (e.g. currency, percentages, counts). This was silently dropped in
v3 when the Redux-based tooltip state was introduced. The
DefaultTooltipContentstill checkedentry.formatteratline 137, but it was never being populated from the graphical item's props.
This change is purely additive — no existing API is changed or removed.
How Has This Been Tested?
test/component/Tooltip/graphicalItem.formatter.spec.tsxwith 7 unit tests covering:formatteris stored in the Redux tooltip payload entry forBarandLineformattertakes precedence over the Tooltip-levelformatterBars where only one hasformatter— only that entry is transformedomnidoc/readProject.spec.tsinline snapshots to include the newformatterpropcommentSimilarityExceptionsentry forLabel/LabelListwhoseformatterprop serves a different purpose(SVG text serialisation)
Screenshots (if appropriate)
N/A — tooltip rendering is covered by unit tests.
Types of changes
Checklist
npm run omnidocto regenerate APIdocs)
Summary by CodeRabbit
New Features
formatterprop to chart components (Area, Bar, Funnel, Line, Scatter, Pie, RadialBar) for per-component tooltip value formatting.Tests