blob: 8e6bff45fbef4b8e1cce1102d3b371b91ec26e08 [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 { 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);
});