test(plugins): regression guards from the migration bug sweep

Adds low-risk import-and-assert tests across migrated plugins, guarding the
classes of bugs found while testing this branch:
- is_timeseries charts must expose a datetime control (calendar, horizon, rose,
  partition). Partition genuinely lacked one, so add sections.legacyTimeseriesTime
  to its control panel (same 500 as paired-t-test otherwise).
- deck.gl Multiple Layers must issue an empty query (self-fetches its layers).
- deck.gl Arc is timeseries only when time_grain_sqla is set.
- Time Pivot's numeric x-axis format must render a number, not the literal
  SMART_NUMBER string.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Evan Rusackas
2026-07-22 17:50:41 -07:00
committed by Claude Code
co-authored by Claude Opus 4.8
parent b887c30573
commit 533f90e4c6
8 changed files with 208 additions and 0 deletions
@@ -0,0 +1,23 @@
/**
* 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 controlPanel from '../src/controlPanel';
test('exposes a datetime column control because the query is is_timeseries', () => {
expect(JSON.stringify(controlPanel)).toContain('granularity_sqla');
});
@@ -0,0 +1,23 @@
/**
* 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 controlPanel from '../src/controlPanel';
test('exposes a datetime column control because the query is is_timeseries', () => {
expect(JSON.stringify(controlPanel)).toContain('granularity_sqla');
});
@@ -27,11 +27,16 @@ import {
D3_TIME_FORMAT_OPTIONS,
DEFAULT_TIME_FORMAT,
getStandardizedControls,
sections,
} from '@superset-ui/chart-controls';
import OptionDescription from './OptionDescription';
const config: ControlPanelConfig = {
controlPanelSections: [
// buildQuery emits is_timeseries when a Time Series option is selected, so
// the query needs a datetime column. Without this section the chart 500s
// with "Datetime column not provided...".
sections.legacyTimeseriesTime,
{
label: t('Query'),
expanded: true,
@@ -0,0 +1,26 @@
/**
* 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 { sections } from '@superset-ui/chart-controls';
import controlPanel from '../src/controlPanel';
test('includes the legacy timeseries Time section (buildQuery can be is_timeseries)', () => {
expect(controlPanel.controlPanelSections).toContain(
sections.legacyTimeseriesTime,
);
});
@@ -0,0 +1,26 @@
/**
* 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 { sections } from '@superset-ui/chart-controls';
import controlPanel from '../src/controlPanel';
test('includes the legacy timeseries Time section (buildQuery can be is_timeseries)', () => {
expect(controlPanel.controlPanelSections).toContain(
sections.legacyTimeseriesTime,
);
});
@@ -0,0 +1,37 @@
/**
* 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 { QueryFormData } from '@superset-ui/core';
import buildQuery from './buildQuery';
const formData: QueryFormData = {
datasource: '1__table',
viz_type: 'deck_multi',
deck_slices: [1, 2],
};
test('deck.gl Multiple Layers issues no query of its own', () => {
// Each layer is a saved chart fetched client-side, so the composed chart must
// emit an empty queries array. That empty response is why metadata sets
// enableNoResults: false, else "No results were returned" hides the map.
expect(buildQuery(formData).queries).toEqual([]);
});
test('deck.gl Multiple Layers emits no query even with no layers selected', () => {
expect(buildQuery({ ...formData, deck_slices: [] }).queries).toEqual([]);
});
@@ -0,0 +1,38 @@
/**
* 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 buildQuery, { DeckArcFormData } from './buildQuery';
const baseFormData: DeckArcFormData = {
datasource: '1__table',
viz_type: 'deck_arc',
start_spatial: { type: 'latlong', lonCol: 'start_lon', latCol: 'start_lat' },
end_spatial: { type: 'latlong', lonCol: 'end_lon', latCol: 'end_lat' },
};
test('Arc buildQuery is not a timeseries query by default', () => {
expect(buildQuery(baseFormData).queries[0].is_timeseries).toBe(false);
});
test('Arc buildQuery is timeseries only when time_grain_sqla is set', () => {
const [query] = buildQuery({
...baseFormData,
time_grain_sqla: 'P1D',
}).queries;
expect(query.is_timeseries).toBe(true);
});
@@ -0,0 +1,30 @@
/**
* 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 { getTimeFormatter } from '@superset-ui/core';
import { getTimeOrNumberFormatter } from '../src/utils';
test('a number format renders a formatted number, not the literal name', () => {
// Time Pivot's x-axis defaults x_axis_format to SMART_NUMBER; NVD3Vis now
// routes it through getTimeOrNumberFormatter (number-aware) rather than
// getTimeFormatter, which would print the literal "SMART_NUMBER" every tick.
expect(getTimeOrNumberFormatter('SMART_NUMBER')(1950000)).toBe('1.95M');
expect(getTimeFormatter('SMART_NUMBER')(new Date(Date.UTC(2024, 0, 1)))).toBe(
'SMART_NUMBER',
);
});