blob: 850df8a55c86bea8e296e5c9912e90cc73fde676 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import {
getChartMetadataRegistry,
ChartMetadata,
Behavior,
} from '@superset-ui/core';
import { nativeFilterGate } from 'src/dashboard/components/nativeFilters/utils';
/**
* Unit tests for chart registry filtering and option generation logic.
* This tests the pure functions used in ChartList for filtering chart types.
*/
describe('Chart Registry Utils', () => {
describe('Type filter option generation', () => {
let registry: ReturnType<typeof getChartMetadataRegistry>;
beforeEach(() => {
registry = getChartMetadataRegistry();
registry.clear();
});
it('generates correct options from chart metadata registry', () => {
// Register test chart types
registry
.registerValue(
'table',
new ChartMetadata({
name: 'Table',
thumbnail: '',
behaviors: [],
}),
)
.registerValue(
'line',
new ChartMetadata({
name: 'Line Chart',
thumbnail: '',
behaviors: [],
}),
)
.registerValue(
'native_filter',
new ChartMetadata({
name: 'Native Filter Chart',
thumbnail: '',
behaviors: [Behavior.NativeFilter],
}),
);
// Generate options like ChartList does
const options = registry
.keys()
.filter(k => nativeFilterGate(registry.get(k)?.behaviors || []))
.map(k => ({ label: registry.get(k)?.name || k, value: k }))
.sort((a, b) => {
if (!a.label || !b.label) return 0;
if (a.label > b.label) return 1;
if (a.label < b.label) return -1;
return 0;
});
expect(options).toEqual([
{ label: 'Line Chart', value: 'line' },
{ label: 'Table', value: 'table' },
]);
// Native filter chart should be filtered out
expect(
options.find(opt => opt.value === 'native_filter'),
).toBeUndefined();
});
it('handles empty registry gracefully', () => {
const options = registry
.keys()
.filter(k => nativeFilterGate(registry.get(k)?.behaviors || []))
.map(k => ({ label: registry.get(k)?.name || k, value: k }));
expect(options).toEqual([]);
});
it('falls back to chart key when name is missing', () => {
registry.registerValue(
'custom_chart',
new ChartMetadata({
name: '', // Empty name
thumbnail: '',
behaviors: [],
}),
);
const options = registry
.keys()
.filter(k => nativeFilterGate(registry.get(k)?.behaviors || []))
.map(k => ({ label: registry.get(k)?.name || k, value: k }));
expect(options).toEqual([
{ label: 'custom_chart', value: 'custom_chart' },
]);
});
it('sorts options alphabetically by label', () => {
registry
.registerValue(
'zebra',
new ChartMetadata({
name: 'Zebra Chart',
thumbnail: '',
behaviors: [],
}),
)
.registerValue(
'apple',
new ChartMetadata({
name: 'Apple Chart',
thumbnail: '',
behaviors: [],
}),
)
.registerValue(
'banana',
new ChartMetadata({
name: 'Banana Chart',
thumbnail: '',
behaviors: [],
}),
);
const options = registry
.keys()
.filter(k => nativeFilterGate(registry.get(k)?.behaviors || []))
.map(k => ({ label: registry.get(k)?.name || k, value: k }))
.sort((a, b) => {
if (!a.label || !b.label) return 0;
if (a.label > b.label) return 1;
if (a.label < b.label) return -1;
return 0;
});
expect(options).toEqual([
{ label: 'Apple Chart', value: 'apple' },
{ label: 'Banana Chart', value: 'banana' },
{ label: 'Zebra Chart', value: 'zebra' },
]);
});
it('handles mixed chart behaviors correctly', () => {
registry
.registerValue(
'regular',
new ChartMetadata({
name: 'Regular Chart',
thumbnail: '',
behaviors: [],
}),
)
.registerValue(
'interactive',
new ChartMetadata({
name: 'Interactive Chart',
thumbnail: '',
behaviors: [Behavior.InteractiveChart],
}),
)
.registerValue(
'native_with_interactive',
new ChartMetadata({
name: 'Native Filter with Interactive',
thumbnail: '',
behaviors: [Behavior.NativeFilter, Behavior.InteractiveChart],
}),
)
.registerValue(
'pure_native',
new ChartMetadata({
name: 'Pure Native Filter',
thumbnail: '',
behaviors: [Behavior.NativeFilter],
}),
);
const options = registry
.keys()
.filter(k => nativeFilterGate(registry.get(k)?.behaviors || []))
.map(k => ({ label: registry.get(k)?.name || k, value: k }))
.sort((a, b) => {
if (!a.label || !b.label) return 0;
if (a.label > b.label) return 1;
if (a.label < b.label) return -1;
return 0;
});
// Should include regular, interactive, and native with interactive
// Should exclude pure native filter
expect(options).toEqual([
{ label: 'Interactive Chart', value: 'interactive' },
{
label: 'Native Filter with Interactive',
value: 'native_with_interactive',
},
{ label: 'Regular Chart', value: 'regular' },
]);
expect(options.find(opt => opt.value === 'pure_native')).toBeUndefined();
});
});
});