Compare commits

...

4 Commits

Author SHA1 Message Date
yousoph
56e85a0350 Merge branch 'master' into fix/dashboard-create-chart-button-spacing 2026-05-12 21:52:55 -07:00
yousoph
135441c263 Merge branch 'master' into fix/dashboard-create-chart-button-spacing 2026-05-12 18:04:36 -07:00
yousoph
567a12bdc9 fix(dashboard): add top padding to "Create new chart" button in builder pane
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 18:25:38 +00:00
Kamil Gabryjelski
c131dd2997 test(heatmap): add tests for tooltip displaying actual axis values
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>
2026-03-11 21:02:12 +00:00
3 changed files with 176 additions and 12 deletions

View File

@@ -18,8 +18,6 @@
*/
import {
NumberFormats,
QueryFormColumn,
getColumnLabel,
getMetricLabel,
getSequentialSchemeRegistry,
getTimeFormatter,
@@ -180,8 +178,6 @@ export default function transformProps(
chartProps;
const {
bottomMargin,
xAxis,
groupby,
linearColorScheme,
leftMargin,
legendType = 'continuous',
@@ -204,9 +200,6 @@ export default function transformProps(
sortYAxis,
} = formData;
const metricLabel = getMetricLabel(metric);
const xAxisLabel = getColumnLabel(xAxis);
// groupby is overridden to be a single value
const yAxisLabel = getColumnLabel(groupby as unknown as QueryFormColumn);
const {
data,
colnames,
@@ -365,8 +358,8 @@ export default function transformProps(
formatter: (params: CallbackDataParams) => {
const totals = calculateTotals(
data,
xAxisLabel,
yAxisLabel,
xAxisColumnName,
yAxisColumnName,
metricLabel,
);
const paramsValue = params.value as (string | number)[];
@@ -392,10 +385,14 @@ export default function transformProps(
let suffix = 'heatmap';
if (typeof value === 'number') {
if (normalizeAcross === 'x') {
percentage = value / totals.x[String(xValue)];
// Convert xValue to a key type (string or number) for totals lookup
const xKey = xValue as string | number;
percentage = value / totals.x[xKey];
suffix = formattedX;
} else if (normalizeAcross === 'y') {
percentage = value / totals.y[String(yValue)];
// Convert yValue to a key type (string or number) for totals lookup
const yKey = yValue as string | number;
percentage = value / totals.y[yKey];
suffix = formattedY;
} else {
percentage = value / totals.total;

View File

@@ -359,4 +359,171 @@ describe('Heatmap transformProps', () => {
);
expect((resultWithoutLegend.echartOptions.legend as any).show).toBe(false);
});
test('tooltip formatter should display actual axis values, not indices', () => {
const chartProps = createChartProps({
sortXAxis: 'alpha_asc',
sortYAxis: 'alpha_asc',
});
const result = transformProps(chartProps as HeatmapChartProps);
const tooltipFormatter = (result.echartOptions.tooltip as any).formatter;
expect(typeof tooltipFormatter).toBe('function');
// Simulate tooltip data: [xIndex, yIndex, value]
// With alpha_asc sorting: xAxis = ['Friday', 'Monday', 'Thursday', 'Tuesday', 'Wednesday']
// yAxis = [9, 10, 11, 14, 15, 16]
// So index [1, 2, 15] should map to 'Monday' and hour 11
const mockParams = {
value: [1, 2, 15],
};
const tooltipHtml = tooltipFormatter(mockParams);
// Tooltip should contain the actual day name 'Monday', not the index '1'
expect(tooltipHtml).toContain('Monday');
// Tooltip should contain the actual hour '11', not the index '2'
expect(tooltipHtml).toContain('11');
// Should not contain raw indices
expect(tooltipHtml).not.toMatch(/\b1\s*\(/);
expect(tooltipHtml).not.toMatch(/\(\s*2\b/);
});
test('tooltip formatter should work with different sort orders', () => {
// Test with descending sort
const chartProps = createChartProps({
sortXAxis: 'alpha_desc',
sortYAxis: 'alpha_desc',
});
const result = transformProps(chartProps as HeatmapChartProps);
const tooltipFormatter = (result.echartOptions.tooltip as any).formatter;
// With alpha_desc sorting: xAxis = ['Wednesday', 'Tuesday', 'Thursday', 'Monday', 'Friday']
// yAxis = [16, 15, 14, 11, 10, 9]
// So index [4, 5, 20] should map to 'Friday' and hour 9
const mockParams = {
value: [4, 5, 20],
};
const tooltipHtml = tooltipFormatter(mockParams);
expect(tooltipHtml).toContain('Friday');
expect(tooltipHtml).toContain('9');
});
test('tooltip formatter should work with value-based sorting', () => {
const chartProps = createChartProps({
sortXAxis: 'value_asc',
sortYAxis: 'value_asc',
});
const result = transformProps(chartProps as HeatmapChartProps);
const tooltipFormatter = (result.echartOptions.tooltip as any).formatter;
// With value_asc sorting on X: ['Wednesday', 'Tuesday', 'Thursday', 'Friday', 'Monday']
// With value_asc sorting on Y: [11, 9, 10, 14, 15, 16]
// So index [0, 0, 8] should map to 'Wednesday' and hour 11
const mockParams = {
value: [0, 0, 8],
};
const tooltipHtml = tooltipFormatter(mockParams);
expect(tooltipHtml).toContain('Wednesday');
expect(tooltipHtml).toContain('11');
});
test('tooltip percentage calculation should use actual values, not indices', () => {
const testData = [
{ day_of_week: 'Monday', hour: 9, count: 10 },
{ day_of_week: 'Monday', hour: 10, count: 20 },
{ day_of_week: 'Tuesday', hour: 9, count: 30 },
];
// Test normalizeAcross: 'x'
const chartPropsX = createChartProps(
{
sortXAxis: 'alpha_asc',
showPercentage: true,
normalizeAcross: 'x',
},
testData,
);
const resultX = transformProps(chartPropsX as HeatmapChartProps);
const tooltipFormatterX = (resultX.echartOptions.tooltip as any).formatter;
// With alpha_asc: xAxis = ['Monday', 'Tuesday'], yAxis = [9, 10]
// Monday total = 30, Tuesday total = 30
// Point [0, 0, 10] = Monday/9 with value 10
// Percentage should be 10/30 = 33.33%, not based on index
const mockParamsX = {
value: [0, 0, 10],
};
const tooltipHtmlX = tooltipFormatterX(mockParamsX);
expect(tooltipHtmlX).toContain('33');
expect(tooltipHtmlX).toContain('%');
// Test normalizeAcross: 'y'
const chartPropsY = createChartProps(
{
sortXAxis: 'alpha_asc',
showPercentage: true,
normalizeAcross: 'y',
},
testData,
);
const resultY = transformProps(chartPropsY as HeatmapChartProps);
const tooltipFormatterY = (resultY.echartOptions.tooltip as any).formatter;
// Hour 9 total = 40 (10 + 30)
// Point [0, 0, 10] = Monday/9 with value 10
// Percentage should be 10/40 = 25%
const mockParamsY = {
value: [0, 0, 10],
};
const tooltipHtmlY = tooltipFormatterY(mockParamsY);
expect(tooltipHtmlY).toContain('25');
expect(tooltipHtmlY).toContain('%');
});
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');
});
});

View File

@@ -118,7 +118,7 @@ const NewChartButtonContainer = styled.div`
${({ theme }) => css`
display: flex;
justify-content: flex-end;
padding-right: ${theme.sizeUnit * 2}px;
padding: ${theme.sizeUnit * 3}px ${theme.sizeUnit * 2}px 0;
`}
`;