mirror of
https://github.com/apache/superset.git
synced 2026-08-04 04:52:32 +00:00
fix(mixed-timeseries): stop duplicating first metric in multi-metric + group-by series names (#40146)
Co-authored-by: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -1161,3 +1161,83 @@ test('x-axis dedup keeps the forced min label when the endpoints format identica
|
||||
|
||||
expect(formatter(min)).toBe('May');
|
||||
});
|
||||
|
||||
test('regression #37921: multi-metric Query A with groupby does not duplicate first metric in series names', () => {
|
||||
// Regression test for https://github.com/apache/superset/issues/37921
|
||||
// ("Residual" follow-up to #37055).
|
||||
//
|
||||
// When Query A has multiple metrics + at least one Group By dimension,
|
||||
// the display-name builder in transformProps.ts used to prepend the FIRST
|
||||
// metric's display name to every series that didn't literally contain it:
|
||||
// name: `${MetricDisplayNameA}, ${entryName}`
|
||||
// For series belonging to the *second* metric, this produced a
|
||||
// cross-contaminated label like `score_one, score_two, A` — the
|
||||
// user-visible "first metric duplicated" symptom in the legend / tooltip.
|
||||
// The fix derives each series' metric from its label-map tuple instead.
|
||||
const multiMetricRows = [
|
||||
{
|
||||
'score_one, A': 1,
|
||||
'score_one, B': 2,
|
||||
'score_two, A': 3,
|
||||
'score_two, B': 4,
|
||||
ds: 599616000000,
|
||||
},
|
||||
{
|
||||
'score_one, A': 5,
|
||||
'score_one, B': 6,
|
||||
'score_two, A': 7,
|
||||
'score_two, B': 8,
|
||||
ds: 599916000000,
|
||||
},
|
||||
];
|
||||
const multiMetricLabelMap = {
|
||||
ds: ['ds'],
|
||||
'score_one, A': ['score_one', 'A'],
|
||||
'score_one, B': ['score_one', 'B'],
|
||||
'score_two, A': ['score_two', 'A'],
|
||||
'score_two, B': ['score_two', 'B'],
|
||||
};
|
||||
|
||||
const queryAData = createTestQueryData(multiMetricRows, {
|
||||
label_map: multiMetricLabelMap,
|
||||
});
|
||||
// Query B keeps the existing single-metric shape — the bug is on
|
||||
// Query A's path so we just need a valid Query B alongside.
|
||||
const queryBData = createTestQueryData(defaultQueryRows, {
|
||||
label_map: defaultLabelMap,
|
||||
});
|
||||
|
||||
const chartProps = createEchartsTimeseriesTestChartProps<
|
||||
EchartsMixedTimeseriesFormData,
|
||||
EchartsMixedTimeseriesProps
|
||||
>({
|
||||
...MIXED_TIMESERIES_CHART_PROPS_DEFAULTS,
|
||||
defaultQueriesData: [queryAData, queryBData],
|
||||
formData: {
|
||||
...formData,
|
||||
metrics: ['score_one', 'score_two'],
|
||||
groupby: ['category'],
|
||||
},
|
||||
queriesData: [queryAData, queryBData],
|
||||
});
|
||||
const transformed = transformProps(chartProps);
|
||||
|
||||
const queryASeriesNames = (transformed.echartOptions.series as any[])
|
||||
.map((s: any) => String(s.name))
|
||||
.filter((n: string) => n.includes('score_'));
|
||||
|
||||
// Each (metric, dim_value) combo from Query A should appear exactly once
|
||||
// with the *correct* metric prefix — not the first-metric-prepended-to-
|
||||
// everything-else form. Comparing the sorted array (rather than using
|
||||
// separate toContain assertions) also catches a regression that emits
|
||||
// duplicate series for the same name.
|
||||
expect([...queryASeriesNames].sort()).toEqual(
|
||||
['score_one, A', 'score_one, B', 'score_two, A', 'score_two, B'].sort(),
|
||||
);
|
||||
|
||||
// And explicitly: no series name should contain *both* metric names —
|
||||
// that's the smoking gun for the duplication bug.
|
||||
for (const name of queryASeriesNames) {
|
||||
expect(name).not.toMatch(/score_one,\s+score_two/);
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user