test(heatmap): add tests for tooltip displaying actual axis values#38522
test(heatmap): add tests for tooltip displaying actual axis values#38522yousoph wants to merge 1 commit intoapache:masterfrom
Conversation
| const formattedValue = valueFormatter(value); | ||
| let percentage = 0; | ||
| let suffix = 'heatmap'; | ||
| if (typeof value === 'number') { | ||
| if (normalizeAcross === 'x') { | ||
| percentage = value / totals.x[x]; | ||
| percentage = value / totals.x[String(xValue)]; | ||
| suffix = formattedX; | ||
| } else if (normalizeAcross === 'y') { | ||
| percentage = value / totals.y[y]; | ||
| percentage = value / totals.y[String(yValue)]; | ||
| suffix = formattedY; | ||
| } else { | ||
| percentage = value / totals.total; |
There was a problem hiding this comment.
Suggestion: When normalizeAcross is 'x' or 'y' (or the whole heatmap), the code divides by the corresponding total without checking if that total is zero or undefined, so cases where all values for an axis (or the whole heatmap) are 0 will produce NaN percentages in the tooltip. [logic error]
Severity Level: Major ⚠️
- ⚠️ Heatmap tooltips show NaN percentage for zero totals.
- ⚠️ Users misinterpret normalized heatmaps with all-zero categories.| const formattedValue = valueFormatter(value); | |
| let percentage = 0; | |
| let suffix = 'heatmap'; | |
| if (typeof value === 'number') { | |
| if (normalizeAcross === 'x') { | |
| percentage = value / totals.x[x]; | |
| percentage = value / totals.x[String(xValue)]; | |
| suffix = formattedX; | |
| } else if (normalizeAcross === 'y') { | |
| percentage = value / totals.y[y]; | |
| percentage = value / totals.y[String(yValue)]; | |
| suffix = formattedY; | |
| } else { | |
| percentage = value / totals.total; | |
| const formattedValue = valueFormatter(value); | |
| let percentage = 0; | |
| let suffix = 'heatmap'; | |
| if (typeof value === 'number') { | |
| if (normalizeAcross === 'x') { | |
| const xTotal = totals.x[String(xValue)] || 0; | |
| percentage = xTotal ? value / xTotal : 0; | |
| suffix = formattedX; | |
| } else if (normalizeAcross === 'y') { | |
| const yTotal = totals.y[String(yValue)] || 0; | |
| percentage = yTotal ? value / yTotal : 0; | |
| suffix = formattedY; | |
| } else { | |
| const total = totals.total || 0; | |
| percentage = total ? value / total : 0; | |
| suffix = 'heatmap'; | |
| } | |
| } |
Steps of Reproduction ✅
1. In `superset-frontend/plugins/plugin-chart-echarts/src/Heatmap/transformProps.ts`, call
the default-exported `transformProps` with `formData.normalizeAcross` set to `'x'` and a
metric configured in `formData.metric` (function definition and `echartOptions`
construction are in this file; tooltip is configured starting at lines 360–405 in the
diff).
2. Provide `queriesData[0].data` such that for at least one x-axis category all metric
values are `0` (e.g., two rows with the same x value, different y values, and metric
column `metricLabel` equal to `0`), so that in `calculateTotals` (lines ~310–336 in the
same file) the corresponding `totals.x[thatXValue]` and the overall `totals.total` remain
`0`.
3. When `transformProps` builds the series data (lines ~330–359), it encodes each data
point as `[xIndex, yIndex, metricValue]`; then ECharts later calls the tooltip formatter
configured at lines 365–405 with a `params` whose `value` is, for the all-zero cell,
`[xIndex, yIndex, 0]`.
4. Inside the tooltip formatter at lines 390–401, the code executes `percentage = value /
totals.x[String(xValue)]` (or `/ totals.y[...]` or `/ totals.total` depending on
`normalizeAcross`); with `value === 0` and the corresponding total being `0`, this
computes `0 / 0`, producing `NaN`, which is then passed to `percentFormatter` and rendered
as a `NaN%` percentage in the tooltip HTML returned by `tooltipHtml`.Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** superset-frontend/plugins/plugin-chart-echarts/src/Heatmap/transformProps.ts
**Line:** 390:401
**Comment:**
*Logic Error: When `normalizeAcross` is `'x'` or `'y'` (or the whole heatmap), the code divides by the corresponding total without checking if that total is zero or undefined, so cases where all values for an axis (or the whole heatmap) are 0 will produce NaN percentages in the tooltip.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.| test('tooltip formatter should handle numeric axes correctly', () => { | ||
| const numericData = [ | ||
| { year: 2020, quarter: 1, revenue: 100 }, | ||
| { year: 2021, quarter: 2, revenue: 150 }, | ||
| { year: 2022, quarter: 3, revenue: 200 }, | ||
| ]; | ||
|
|
||
| const chartProps = createChartProps( | ||
| { | ||
| sortXAxis: 'alpha_asc', | ||
| sortYAxis: 'alpha_asc', | ||
| xAxis: 'year', | ||
| groupby: ['quarter'], | ||
| }, | ||
| numericData, | ||
| ); | ||
|
|
||
| (chartProps as any).queriesData[0].colnames = [ | ||
| 'year', | ||
| 'quarter', | ||
| 'revenue', | ||
| ]; | ||
|
|
||
| const result = transformProps(chartProps as HeatmapChartProps); | ||
| const tooltipFormatter = (result.echartOptions.tooltip as any).formatter; | ||
|
|
||
| // With alpha_asc: xAxis = [2020, 2021, 2022], yAxis = [1, 2, 3] | ||
| // Index [1, 1, 150] should map to year 2021 and quarter 2 | ||
| const mockParams = { | ||
| value: [1, 1, 150], | ||
| }; | ||
|
|
||
| const tooltipHtml = tooltipFormatter(mockParams); | ||
|
|
||
| expect(tooltipHtml).toContain('2021'); | ||
| expect(tooltipHtml).toContain('2'); | ||
| }); |
There was a problem hiding this comment.
Suggestion: In the numeric-axes tooltip test, the formData metric is left as 'count' while the data and colnames use 'revenue', so transformProps reads undefined metric values and computes incorrect totals, making the test setup inconsistent with real usage and potentially hiding issues in percentage logic. [logic error]
Severity Level: Major ⚠️
- ⚠️ Heatmap numeric-axis tooltip test uses inconsistent metric configuration.
- ⚠️ Misconfigured test may miss regressions in metric-based logic.| test('tooltip formatter should handle numeric axes correctly', () => { | |
| const numericData = [ | |
| { year: 2020, quarter: 1, revenue: 100 }, | |
| { year: 2021, quarter: 2, revenue: 150 }, | |
| { year: 2022, quarter: 3, revenue: 200 }, | |
| ]; | |
| const chartProps = createChartProps( | |
| { | |
| sortXAxis: 'alpha_asc', | |
| sortYAxis: 'alpha_asc', | |
| xAxis: 'year', | |
| groupby: ['quarter'], | |
| }, | |
| numericData, | |
| ); | |
| (chartProps as any).queriesData[0].colnames = [ | |
| 'year', | |
| 'quarter', | |
| 'revenue', | |
| ]; | |
| const result = transformProps(chartProps as HeatmapChartProps); | |
| const tooltipFormatter = (result.echartOptions.tooltip as any).formatter; | |
| // With alpha_asc: xAxis = [2020, 2021, 2022], yAxis = [1, 2, 3] | |
| // Index [1, 1, 150] should map to year 2021 and quarter 2 | |
| const mockParams = { | |
| value: [1, 1, 150], | |
| }; | |
| const tooltipHtml = tooltipFormatter(mockParams); | |
| expect(tooltipHtml).toContain('2021'); | |
| expect(tooltipHtml).toContain('2'); | |
| }); | |
| test('tooltip formatter should handle numeric axes correctly', () => { | |
| const numericData = [ | |
| { year: 2020, quarter: 1, revenue: 100 }, | |
| { year: 2021, quarter: 2, revenue: 150 }, | |
| { year: 2022, quarter: 3, revenue: 200 }, | |
| ]; | |
| const chartProps = createChartProps( | |
| { | |
| sortXAxis: 'alpha_asc', | |
| sortYAxis: 'alpha_asc', | |
| xAxis: 'year', | |
| groupby: ['quarter'], | |
| metric: 'revenue', | |
| }, | |
| numericData, | |
| ); | |
| (chartProps as any).queriesData[0].colnames = [ | |
| 'year', | |
| 'quarter', | |
| 'revenue', | |
| ]; | |
| const result = transformProps(chartProps as HeatmapChartProps); | |
| const tooltipFormatter = (result.echartOptions.tooltip as any).formatter; | |
| // With alpha_asc: xAxis = [2020, 2021, 2022], yAxis = [1, 2, 3] | |
| // Index [1, 1, 150] should map to year 2021 and quarter 2 | |
| const mockParams = { | |
| value: [1, 1, 150], | |
| }; | |
| const tooltipHtml = tooltipFormatter(mockParams); | |
| expect(tooltipHtml).toContain('2021'); | |
| expect(tooltipHtml).toContain('2'); | |
| }); |
Steps of Reproduction ✅
1. Run the unit tests for the heatmap transform via `npm test -- transformProps.test.ts`
in `superset-frontend/plugins/plugin-chart-echarts/test/Heatmap/transformProps.test.ts`.
2. Observe the test `tooltip formatter should handle numeric axes correctly` starting at
line 492, which calls `createChartProps` without overriding `metric`, so it uses
`baseFormData.metric = 'count'` from the top of the file.
3. In the same test, `numericData` only contains a `revenue` field and
`queriesData[0].colnames` is overridden to `['year', 'quarter', 'revenue']`, so there is
no `count` column for the metric referenced by formData.
4. When `transformProps` is invoked with these `chartProps`, it computes heatmap series
values and any metric-based aggregations using the nonexistent `'count'` metric (reading
undefined/incorrect values), while the test only asserts on axis labels in the tooltip
output, so this inconsistent setup is not detected by the assertions.Prompt for AI Agent 🤖
This is a comment left during a code review.
**Path:** superset-frontend/plugins/plugin-chart-echarts/test/Heatmap/transformProps.test.ts
**Line:** 492:528
**Comment:**
*Logic Error: In the numeric-axes tooltip test, the formData metric is left as `'count'` while the data and `colnames` use `'revenue'`, so `transformProps` reads undefined metric values and computes incorrect totals, making the test setup inconsistent with real usage and potentially hiding issues in percentage logic.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.There was a problem hiding this comment.
Code Review Agent Run #746e1e
Actionable Suggestions - 1
-
superset-frontend/plugins/plugin-chart-echarts/src/Heatmap/transformProps.ts - 1
- Fix index type conversion · Line 375-376
Review Details
-
Files reviewed - 2 · Commit Range:
e508645..4d5d74f- superset-frontend/plugins/plugin-chart-echarts/src/Heatmap/transformProps.ts
- superset-frontend/plugins/plugin-chart-echarts/test/Heatmap/transformProps.test.ts
-
Files skipped - 0
-
Tools
- Eslint (Linter) - ✔︎ Successful
- Whispers (Secret Scanner) - ✔︎ Successful
- Detect-secrets (Secret Scanner) - ✔︎ Successful
Bito Usage Guide
Commands
Type the following command in the pull request comment and save the comment.
-
/review- Manually triggers a full AI review. -
/pause- Pauses automatic reviews on this pull request. -
/resume- Resumes automatic reviews. -
/resolve- Marks all Bito-posted review comments as resolved. -
/abort- Cancels all in-progress reviews.
Refer to the documentation for additional commands.
Configuration
This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.
Documentation & Help
| const xIndex = paramsValue?.[0] as number; | ||
| const yIndex = paramsValue?.[1] as number; |
There was a problem hiding this comment.
The type assertion 'as number' doesn't perform runtime conversion. If params.value[0] is a string (e.g., '1'), xIndex remains a string, causing sortedXAxisValues['1'] to be undefined instead of sortedXAxisValues[1]. This could lead to empty axis labels and NaN percentages in tooltips. Use Number() for proper conversion.
Code suggestion
Check the AI-generated fix before applying
| const xIndex = paramsValue?.[0] as number; | |
| const yIndex = paramsValue?.[1] as number; | |
| const xIndex = Number(paramsValue?.[0]); | |
| const yIndex = Number(paramsValue?.[1]); |
Code Review Run #746e1e
Should Bito avoid suggestions like this for future reviews? (Manage Rules)
- Yes, avoid them
4d5d74f to
84c2e5d
Compare
Code Review Agent Run #80dbcdActionable Suggestions - 0Review Details
Bito Usage GuideCommands Type the following command in the pull request comment and save the comment.
Refer to the documentation for additional commands. Configuration This repository uses Documentation & Help |
Add comprehensive tests to ensure the tooltip formatter correctly displays actual axis values instead of numeric indices. This prevents regression of the bug fixed in the previous commit where tooltips showed "0 (1)" instead of actual labels like "Monday (Morning)". Tests cover: - Tooltip displays actual axis values with alphabetical sorting - Tooltip works correctly with different sort orders (asc/desc) - Tooltip works correctly with value-based sorting - Percentage calculations use actual values when normalizeAcross is enabled - Tooltip handles numeric axes correctly Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
84c2e5d to
076f85d
Compare
There was a problem hiding this comment.
Code Review Agent Run #e016ae
Actionable Suggestions - 1
-
superset-frontend/plugins/plugin-chart-echarts/test/Heatmap/transformProps.test.ts - 1
- Test data mismatch · Line 499-507
Review Details
-
Files reviewed - 2 · Commit Range:
076f85d..076f85d- superset-frontend/plugins/plugin-chart-echarts/src/Heatmap/transformProps.ts
- superset-frontend/plugins/plugin-chart-echarts/test/Heatmap/transformProps.test.ts
-
Files skipped - 0
-
Tools
- Whispers (Secret Scanner) - ✔︎ Successful
- Detect-secrets (Secret Scanner) - ✔︎ Successful
- Eslint (Linter) - ✔︎ Successful
Bito Usage Guide
Commands
Type the following command in the pull request comment and save the comment.
-
/review- Manually triggers a full AI review. -
/pause- Pauses automatic reviews on this pull request. -
/resume- Resumes automatic reviews. -
/resolve- Marks all Bito-posted review comments as resolved. -
/abort- Cancels all in-progress reviews.
Refer to the documentation for additional commands.
Configuration
This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.
Documentation & Help
| const chartProps = createChartProps( | ||
| { | ||
| sortXAxis: 'alpha_asc', | ||
| sortYAxis: 'alpha_asc', | ||
| xAxis: 'year', | ||
| groupby: ['quarter'], | ||
| }, | ||
| numericData, | ||
| ); |
There was a problem hiding this comment.
The test uses custom data with 'revenue' as the metric column, but the formData still defaults to metric: 'count'. This mismatch will cause the transformProps to look for 'count' in the data, resulting in empty or incorrect axis values and failing assertions.
Code Review Run #e016ae
Should Bito avoid suggestions like this for future reviews? (Manage Rules)
- Yes, avoid them
User description
SUMMARY
Adds comprehensive regression tests for the heatmap tooltip bug fix where tooltips were displaying numeric indices (0, 1, 2...) instead of actual axis values (e.g., "Monday", "Morning").
Context: After PR #36302 changed the heatmap data structure to use axis indices for proper sorting, the tooltip formatter was not updated to look up actual values from the sorted arrays. This caused tooltips to display raw indices instead of formatted axis labels.
What this PR does:
normalizeAcrossis enabledWhy these tests matter:
These tests prevent future regressions by verifying the tooltip formatter correctly:
sortedXAxisValuesandsortedYAxisValuesarraystotals.x[xValue]andtotals.y[yValue]BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF
N/A - Test-only changes
TESTING INSTRUCTIONS
CodeAnt-AI Description
Fix heatmap tooltip to show actual axis labels and correct percentage calculations
What Changed
Impact
✅ Clearer heatmap tooltips✅ Correct heatmap percentage values✅ Fewer tooltip regressions💡 Usage Guide
Checking Your Pull Request
Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.
Talking to CodeAnt AI
Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:
This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.
Example
Preserve Org Learnings with CodeAnt
You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:
This helps CodeAnt AI learn and adapt to your team's coding style and standards.
Example
Retrigger review
Ask CodeAnt AI to review the PR again, by typing:
Check Your Repository Health
To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.