From 1a34752e9e8d7ed47d07d8bf3e9cf8a02c76ebbf Mon Sep 17 00:00:00 2001 From: Enzo Martellucci Date: Thu, 20 Aug 2026 16:25:27 +0200 Subject: [PATCH] test(dashboard-v2): lock the balloons control schema shape end-to-end Adds an integration test that mirrors the real nested $defs/$ref shape Balloons.get_control_schema() serves (per test_get_control_schema_base_shape), locking in the contract between the backend's x-control annotations (Task 1) and the frontend's column/metric-multi and column pickers (Tasks 3-4). Co-Authored-By: Claude Sonnet 5 --- .../SchemaControlPanel.test.tsx | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/superset-frontend/src/pages/DashboardBuilderV2/SchemaControlPanel.test.tsx b/superset-frontend/src/pages/DashboardBuilderV2/SchemaControlPanel.test.tsx index bf2110b0205..257f380beca 100644 --- a/superset-frontend/src/pages/DashboardBuilderV2/SchemaControlPanel.test.tsx +++ b/superset-frontend/src/pages/DashboardBuilderV2/SchemaControlPanel.test.tsx @@ -306,3 +306,62 @@ test('falls back to the raw JSON editor when an existing metric entry is an ad-h // confirms the fallback fired instead of the picker. expect(screen.queryByRole('combobox')).not.toBeInTheDocument(); }); + +test('the real balloons schema shape (dataBinding nested under $defs) renders pickers for dimensions, metrics, and colorDimension', async () => { + postSpy.mockResolvedValue({ + json: { + result: { + type: 'object', + properties: { + dataBinding: { $ref: '#/$defs/DataBinding' }, + colorDimension: { + type: 'string', + title: 'Color dimension', + 'x-control': 'column', + }, + }, + $defs: { + DataBinding: { + type: 'object', + properties: { + datasetId: { type: 'integer', title: 'Dataset ID' }, + metrics: { + type: 'array', + title: 'Metrics', + 'x-control': 'metric-multi', + }, + dimensions: { + type: 'array', + title: 'Dimensions', + 'x-control': 'column-multi', + }, + }, + }, + }, + }, + }, + } as never); + getSpy.mockResolvedValue({ + json: { + result: { + columns: [{ column_name: 'gender', type_generic: 1 }], + metrics: [{ metric_name: 'count', verbose_name: 'Count' }], + }, + }, + } as never); + + // `metrics`/`dimensions` are pre-filled with the only known metric/column + // so neither's "Add field" select renders — otherwise `selectOption` + // would find three comboboxes (dimensions' add-select, metrics' + // add-select, and colorDimension's) instead of the one it expects. + const id = mount('balloons', { + dataBinding: { datasetId: 1, metrics: ['count'], dimensions: ['gender'] }, + }); + + await screen.findByText('Color dimension'); + await selectOption('gender'); + + await waitFor(() => + expect(provider.getNode(id)?.props?.colorDimension).toBe('gender'), + ); +});