This is an automated email from the ASF dual-hosted git repository.

sadpandajoe pushed a commit to branch explore-rtl-control-deps
in repository https://gitbox.apache.org/repos/asf/superset.git

commit 42a53a24f34a2102218aa03e321d998c41761108
Author: Joe Li <[email protected]>
AuthorDate: Wed Sep 30 17:02:48 2026 -0700

    test(explore): tighten viz switch assertions and pin object-form control 
filtering
    
    Assert the reducer builds the target viz's control state, cover
    formDataOverrides receiving standardized metrics and columns, and pin
    that getSectionsToRender only filters string control references.
    
    Co-Authored-By: Claude Opus 5.5 <[email protected]>
---
 .../components/ControlPanelsContainer.test.tsx     | 50 +++++++++++++++++-
 .../controlUtils/getSectionsToRender.test.ts       | 60 +++++++++++++++++++++-
 2 files changed, 107 insertions(+), 3 deletions(-)

diff --git 
a/superset-frontend/src/explore/components/ControlPanelsContainer.test.tsx 
b/superset-frontend/src/explore/components/ControlPanelsContainer.test.tsx
index 1e0cd5e630d..75eef10905d 100644
--- a/superset-frontend/src/explore/components/ControlPanelsContainer.test.tsx
+++ b/superset-frontend/src/explore/components/ControlPanelsContainer.test.tsx
@@ -27,11 +27,13 @@ import {
 } from 'spec/helpers/testing-library';
 import reducerIndex from 'spec/helpers/reducerIndex';
 import { t } from '@apache-superset/core/translation';
+import { getStandardizedControls } from '@superset-ui/chart-controls';
 import {
   DatasourceType,
   getChartControlPanelRegistry,
   isFeatureEnabled,
   FeatureFlag,
+  QueryFormData,
 } from '@superset-ui/core';
 import {
   defaultControls,
@@ -153,8 +155,30 @@ describe('ControlPanelsContainer', () => {
     ],
   };
 
+  // Consumes the standardized metrics/columns under field names the source viz
+  // never had, so values can only arrive through the StandardizedFormData
+  // transform and not by copying same-named form_data keys.
+  const switchMappedConfig = {
+    controlPanelSections: [
+      {
+        label: t('Query'),
+        expanded: true,
+        controlSetRows: [['size'], ['series_columns']],
+      },
+    ],
+    formDataOverrides: (formData: QueryFormData) => ({
+      ...formData,
+      size: getStandardizedControls().shiftMetric(),
+      series_columns: getStandardizedControls().popAllColumns(),
+    }),
+  };
+
   beforeEach(() => {
     getChartControlPanelRegistry().registerValue('table', defaultTableConfig);
+    getChartControlPanelRegistry().registerValue(
+      'switch-mapped',
+      switchMappedConfig,
+    );
     getChartControlPanelRegistry().registerValue(
       'switch-target',
       switchTargetConfig,
@@ -167,6 +191,7 @@ describe('ControlPanelsContainer', () => {
   afterEach(() => {
     getChartControlPanelRegistry().remove('table');
     getChartControlPanelRegistry().remove('switch-target');
+    getChartControlPanelRegistry().remove('switch-mapped');
     jest.clearAllMocks();
   });
 
@@ -737,19 +762,24 @@ describe('ControlPanelsContainer', () => {
       await screen.findByRole('button', { name: /group by/i }),
     ).toBeInTheDocument();
     expect(screen.queryByText(/series limit/i)).not.toBeInTheDocument();
+    expect(
+      (store.getState() as ExplorePageState).explore.controls.limit,
+    ).toBeUndefined();
 
     act(() => {
       store.dispatch(setControlValue('viz_type', 'switch-target'));
     });
 
-    // `limit` exists only in the target viz, so its control is rendered from
-    // the control state the reducer built for that viz.
     expect(
       (await screen.findAllByText(/series limit/i)).length,
     ).toBeGreaterThan(0);
     expect(
       screen.queryByRole('button', { name: /group by/i }),
     ).not.toBeInTheDocument();
+    // The label above comes from the registered panel config, so also check 
the
+    // reducer built control state for `limit`, which only the target viz has.
+    const { controls } = (store.getState() as ExplorePageState).explore;
+    expect(controls.limit).toMatchObject({ label: 'Series limit' });
   });
 
   test('switching viz_type carries shared metrics and groupby over and drops 
controls the new viz lacks', async () => {
@@ -775,4 +805,20 @@ describe('ControlPanelsContainer', () => {
     expect(controls.all_columns).toBeUndefined();
     expect(formData.all_columns).toBeUndefined();
   });
+
+  test('switching viz_type hands standardized metrics and columns to the 
target formDataOverrides', async () => {
+    const store = createStoreBackedExplore();
+    render(<StoreBackedControlPanelsContainer />, { store });
+    await screen.findByRole('button', { name: /group by/i });
+
+    act(() => {
+      store.dispatch(setControlValue('viz_type', 'switch-mapped'));
+    });
+
+    const { form_data: formData } = (store.getState() as ExplorePageState)
+      .explore;
+    expect(formData.viz_type).toBe('switch-mapped');
+    expect(formData.size).toBe('count');
+    expect(formData.series_columns).toEqual(['name', 'gender']);
+  });
 });
diff --git 
a/superset-frontend/src/explore/controlUtils/getSectionsToRender.test.ts 
b/superset-frontend/src/explore/controlUtils/getSectionsToRender.test.ts
index fba9e0af1f2..f2a5c0dfd46 100644
--- a/superset-frontend/src/explore/controlUtils/getSectionsToRender.test.ts
+++ b/superset-frontend/src/explore/controlUtils/getSectionsToRender.test.ts
@@ -20,7 +20,10 @@ import {
   DatasourceType,
   getChartControlPanelRegistry,
 } from '@superset-ui/core';
-import { ControlPanelConfig } from '@superset-ui/chart-controls';
+import {
+  ControlPanelConfig,
+  sharedControls,
+} from '@superset-ui/chart-controls';
 import { getSectionsToRender } from './getSectionsToRender';
 
 const VIZ_TYPE = 'sections-to-render-test-viz';
@@ -55,6 +58,31 @@ function namesInSection(datasourceType: DatasourceType): 
string[] {
     .filter((name): name is string => Boolean(name));
 }
 
+const OBJECT_FORM_SECTION_LABEL = 'Object form controls';
+
+// Mix of string references (filtered by datasource type) and the object form
+// that real chart plugins use for the same controls.
+const objectFormConfig: ControlPanelConfig = {
+  controlPanelSections: [
+    {
+      label: OBJECT_FORM_SECTION_LABEL,
+      expanded: true,
+      controlSetRows: [
+        ['granularity'],
+        ['granularity_sqla'],
+        [{ name: 'granularity', config: sharedControls.granularity }],
+        [
+          {
+            name: 'granularity_sqla',
+            config: sharedControls.granularity_sqla,
+          },
+          { name: 'time_grain_sqla', config: sharedControls.time_grain_sqla },
+        ],
+      ],
+    },
+  ],
+};
+
 beforeEach(() => {
   getChartControlPanelRegistry().registerValue(VIZ_TYPE, controlConfig);
 });
@@ -119,3 +147,33 @@ test('returns only the default sections for an 
unregistered viz type', () => {
   expect(sections.map(section => section?.label)).not.toContain(SECTION_LABEL);
   expect(sections.length).toBeGreaterThan(0);
 });
+
+test.each([
+  [
+    DatasourceType.Table,
+    ['granularity_sqla', 'granularity', 'granularity_sqla', 'time_grain_sqla'],
+  ],
+  [
+    DatasourceType.SemanticView,
+    ['granularity_sqla', 'granularity', 'granularity_sqla', 'time_grain_sqla'],
+  ],
+  [
+    DatasourceType.Dataset,
+    ['granularity', 'granularity', 'granularity_sqla', 'time_grain_sqla'],
+  ],
+])(
+  'documents that only string control references are filtered, object-form 
controls pass through, for %s datasources',
+  (datasourceType, expectedNames) => {
+    getChartControlPanelRegistry().registerValue(VIZ_TYPE, objectFormConfig);
+
+    const section = getSectionsToRender(VIZ_TYPE, datasourceType).find(
+      item => item?.label === OBJECT_FORM_SECTION_LABEL,
+    );
+    const rows = (section?.controlSetRows ?? []) as ExpandedRow[];
+    const names = rows
+      .flat()
+      .map(item => (typeof item === 'string' ? item : item?.name));
+
+    expect(names).toEqual(expectedNames);
+  },
+);

Reply via email to