/** * 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 { ControlPanelState } from '../../src/types'; // Mock the utilities to avoid complex dependencies jest.mock('../../src/utils', () => ({ formatSelectOptions: jest.fn((options: any[]) => options.map((opt: any) => [opt, opt]), ), displayTimeRelatedControls: jest.fn(() => true), getColorControlsProps: jest.fn(() => ({})), D3_FORMAT_OPTIONS: [], D3_FORMAT_DOCS: '', D3_TIME_FORMAT_OPTIONS: [], D3_TIME_FORMAT_DOCS: '', DEFAULT_TIME_FORMAT: '%Y-%m-%d', DEFAULT_NUMBER_FORMAT: '', })); // Mock shared controls const mockSharedControls = { matrixify_dimension_x: { shouldMapStateToProps: ( prevState: ControlPanelState, state: ControlPanelState, ) => { const fieldsToCheck = [ 'matrixify_topn_value_x', 'matrixify_topn_metric_x', 'matrixify_topn_order_x', 'matrixify_dimension_selection_mode_x', ]; return fieldsToCheck.some( field => prevState?.form_data?.[field] !== state?.form_data?.[field], ); }, mapStateToProps: ({ datasource, controls, form_data }: any) => { const getValue = (key: string, defaultValue?: any) => form_data?.[key] ?? controls?.[key]?.value ?? defaultValue; return { datasource, selectionMode: getValue( 'matrixify_dimension_selection_mode_x', 'members', ), topNMetric: getValue('matrixify_topn_metric_x'), topNValue: getValue('matrixify_topn_value_x'), topNOrder: getValue('matrixify_topn_order_x'), formData: form_data, }; }, }, matrixify_dimension_y: { shouldMapStateToProps: ( prevState: ControlPanelState, state: ControlPanelState, ) => { const fieldsToCheck = [ 'matrixify_topn_value_y', 'matrixify_topn_metric_y', 'matrixify_topn_order_y', 'matrixify_dimension_selection_mode_y', ]; return fieldsToCheck.some( field => prevState?.form_data?.[field] !== state?.form_data?.[field], ); }, mapStateToProps: ({ datasource, controls, form_data }: any) => { const getValue = (key: string, defaultValue?: any) => form_data?.[key] ?? controls?.[key]?.value ?? defaultValue; return { datasource, selectionMode: getValue( 'matrixify_dimension_selection_mode_y', 'members', ), topNMetric: getValue('matrixify_topn_metric_y'), topNValue: getValue('matrixify_topn_value_y'), topNOrder: getValue('matrixify_topn_order_y'), formData: form_data, }; }, }, }; const createMockState = ( formData: any = {}, controls: any = {}, ): ControlPanelState => ({ slice: { slice_id: 123 }, form_data: formData, datasource: null, controls, common: {}, metadata: {}, }); const createMockControlState = (value: any = null) => ({ value }); test('matrixify_dimension_x should return true when topN value changes', () => { const control = mockSharedControls.matrixify_dimension_x; const prevState = createMockState({ matrixify_topn_value_x: 5, matrixify_topn_metric_x: 'metric1', matrixify_topn_order_x: 'desc', matrixify_dimension_selection_mode_x: 'topn', }); const nextState = createMockState({ matrixify_topn_value_x: 10, // Changed matrixify_topn_metric_x: 'metric1', matrixify_topn_order_x: 'desc', matrixify_dimension_selection_mode_x: 'topn', }); expect(control.shouldMapStateToProps!(prevState, nextState)).toBe(true); }); test('matrixify_dimension_x should return true when topN metric changes', () => { const control = mockSharedControls.matrixify_dimension_x; const prevState = createMockState({ matrixify_topn_value_x: 5, matrixify_topn_metric_x: 'metric1', matrixify_topn_order_x: 'desc', matrixify_dimension_selection_mode_x: 'topn', }); const nextState = createMockState({ matrixify_topn_value_x: 5, matrixify_topn_metric_x: 'metric2', // Changed matrixify_topn_order_x: 'desc', matrixify_dimension_selection_mode_x: 'topn', }); expect(control.shouldMapStateToProps!(prevState, nextState)).toBe(true); }); test('matrixify_dimension_x should return true when topN order changes', () => { const control = mockSharedControls.matrixify_dimension_x; const prevState = createMockState({ matrixify_topn_value_x: 5, matrixify_topn_metric_x: 'metric1', matrixify_topn_order_x: 'desc', matrixify_dimension_selection_mode_x: 'topn', }); const nextState = createMockState({ matrixify_topn_value_x: 5, matrixify_topn_metric_x: 'metric1', matrixify_topn_order_x: 'asc', // Changed matrixify_dimension_selection_mode_x: 'topn', }); expect(control.shouldMapStateToProps!(prevState, nextState)).toBe(true); }); test('matrixify_dimension_x should return true when selection mode changes', () => { const control = mockSharedControls.matrixify_dimension_x; const prevState = createMockState({ matrixify_topn_value_x: 5, matrixify_topn_metric_x: 'metric1', matrixify_topn_order_x: 'desc', matrixify_dimension_selection_mode_x: 'topn', }); const nextState = createMockState({ matrixify_topn_value_x: 5, matrixify_topn_metric_x: 'metric1', matrixify_topn_order_x: 'desc', matrixify_dimension_selection_mode_x: 'members', // Changed }); expect(control.shouldMapStateToProps!(prevState, nextState)).toBe(true); }); test('matrixify_dimension_x should return false when no relevant fields change', () => { const control = mockSharedControls.matrixify_dimension_x; const prevState = createMockState({ matrixify_topn_value_x: 5, matrixify_topn_metric_x: 'metric1', matrixify_topn_order_x: 'desc', matrixify_dimension_selection_mode_x: 'topn', unrelated_field: 'value1', }); const nextState = createMockState({ matrixify_topn_value_x: 5, matrixify_topn_metric_x: 'metric1', matrixify_topn_order_x: 'desc', matrixify_dimension_selection_mode_x: 'topn', unrelated_field: 'value2', // Changed, but not relevant }); expect(control.shouldMapStateToProps!(prevState, nextState)).toBe(false); }); test('matrixify_dimension_x should return false when states are identical', () => { const control = mockSharedControls.matrixify_dimension_x; const state = createMockState({ matrixify_topn_value_x: 5, matrixify_topn_metric_x: 'metric1', matrixify_topn_order_x: 'desc', matrixify_dimension_selection_mode_x: 'topn', }); expect(control.shouldMapStateToProps!(state, state)).toBe(false); }); test('matrixify_dimension_x should handle missing form_data gracefully', () => { const control = mockSharedControls.matrixify_dimension_x; const prevState = createMockState(); // No form_data const nextState = createMockState({ matrixify_topn_value_x: 5, }); expect(control.shouldMapStateToProps!(prevState, nextState)).toBe(true); }); test('matrixify_dimension_x should handle undefined values gracefully', () => { const control = mockSharedControls.matrixify_dimension_x; const prevState = createMockState({ matrixify_topn_value_x: undefined, matrixify_topn_metric_x: null, }); const nextState = createMockState({ matrixify_topn_value_x: 5, matrixify_topn_metric_x: 'metric1', }); expect(control.shouldMapStateToProps!(prevState, nextState)).toBe(true); }); test('matrixify_dimension_y should check y-axis specific fields', () => { const control = mockSharedControls.matrixify_dimension_y; const prevState = createMockState({ matrixify_topn_value_y: 5, matrixify_topn_metric_y: 'metric1', }); const nextState = createMockState({ matrixify_topn_value_y: 10, // Changed matrixify_topn_metric_y: 'metric1', }); expect(control.shouldMapStateToProps!(prevState, nextState)).toBe(true); }); test('matrixify_dimension_y should not trigger on x-axis changes', () => { const control = mockSharedControls.matrixify_dimension_y; const prevState = createMockState({ matrixify_topn_value_x: 5, // x-axis field matrixify_topn_value_y: 5, // y-axis field (unchanged) }); const nextState = createMockState({ matrixify_topn_value_x: 10, // x-axis field changed matrixify_topn_value_y: 5, // y-axis field (unchanged) }); expect(control.shouldMapStateToProps!(prevState, nextState)).toBe(false); }); test('mapStateToProps should map form_data values correctly', () => { const control = mockSharedControls.matrixify_dimension_x; const state = createMockState({ matrixify_dimension_selection_mode_x: 'topn', matrixify_topn_metric_x: 'metric1', matrixify_topn_value_x: 10, matrixify_topn_order_x: 'desc', }); const mockDatasource: any = { id: 1, columns: [] }; state.datasource = mockDatasource; const result = control.mapStateToProps!(state); expect(result).toEqual({ datasource: mockDatasource, selectionMode: 'topn', topNMetric: 'metric1', topNValue: 10, topNOrder: 'desc', formData: state.form_data, }); }); test('mapStateToProps should fall back to control values when form_data is missing', () => { const control = mockSharedControls.matrixify_dimension_x; const state = createMockState( {}, // Empty form_data { matrixify_dimension_selection_mode_x: createMockControlState('members'), matrixify_topn_metric_x: createMockControlState('metric2'), matrixify_topn_value_x: createMockControlState(15), }, ); const result = control.mapStateToProps!(state); expect(result.selectionMode).toBe('members'); expect(result.topNMetric).toBe('metric2'); expect(result.topNValue).toBe(15); }); test('mapStateToProps should use default values when both form_data and controls are missing', () => { const control = mockSharedControls.matrixify_dimension_x; const state = createMockState({}, {}); const result = control.mapStateToProps!(state); expect(result.selectionMode).toBe('members'); // Default value expect(result.topNMetric).toBeUndefined(); expect(result.topNValue).toBeUndefined(); expect(result.topNOrder).toBeUndefined(); }); test('mapStateToProps should prioritize form_data over control values', () => { const control = mockSharedControls.matrixify_dimension_x; const state = createMockState( { matrixify_dimension_selection_mode_x: 'topn', // form_data value }, { matrixify_dimension_selection_mode_x: createMockControlState('members'), // control value }, ); const result = control.mapStateToProps!(state); expect(result.selectionMode).toBe('topn'); // Should use form_data value }); test('should efficiently check only relevant fields', () => { const control = mockSharedControls.matrixify_dimension_x; const prevState = createMockState({ // Many fields, only some relevant field1: 'value1', field2: 'value2', matrixify_topn_value_x: 5, // Relevant field3: 'value3', matrixify_topn_metric_x: 'metric1', // Relevant field4: 'value4', matrixify_other_control: 'value5', }); const nextState = createMockState({ field1: 'value1_changed', // Not relevant field2: 'value2_changed', // Not relevant matrixify_topn_value_x: 5, // Relevant, unchanged field3: 'value3_changed', // Not relevant matrixify_topn_metric_x: 'metric1', // Relevant, unchanged field4: 'value4_changed', // Not relevant matrixify_other_control: 'value5_changed', // Not relevant }); // Should return false because no relevant fields changed expect(control.shouldMapStateToProps!(prevState, nextState)).toBe(false); });