diff --git a/frontend/src/container/NewDashboard/DashboardVariablesSelection/VariableItem.test.tsx b/frontend/src/container/NewDashboard/DashboardVariablesSelection/VariableItem.test.tsx
new file mode 100644
index 0000000000..148591c568
--- /dev/null
+++ b/frontend/src/container/NewDashboard/DashboardVariablesSelection/VariableItem.test.tsx
@@ -0,0 +1,168 @@
+import '@testing-library/jest-dom/extend-expect';
+
+import { fireEvent, render, screen } from '@testing-library/react';
+import React from 'react';
+import { IDashboardVariable } from 'types/api/dashboard/getAll';
+
+import VariableItem from './VariableItem';
+
+const mockVariableData: IDashboardVariable = {
+ description: 'Test Variable',
+ type: 'TEXTBOX',
+ textboxValue: 'defaultValue',
+ sort: 'DISABLED',
+ multiSelect: false,
+ showALLOption: false,
+ name: 'testVariable',
+};
+
+// New mock data for a custom variable
+const mockCustomVariableData: IDashboardVariable = {
+ ...mockVariableData,
+ name: 'customVariable',
+ type: 'CUSTOM',
+ customValue: 'option1,option2,option3',
+};
+
+const mockOnValueUpdate = jest.fn();
+const mockOnAllSelectedUpdate = jest.fn();
+
+describe('VariableItem', () => {
+ let useEffectSpy: jest.SpyInstance;
+
+ beforeEach(() => {
+ useEffectSpy = jest.spyOn(React, 'useEffect');
+ });
+
+ afterEach(() => {
+ jest.clearAllMocks();
+ useEffectSpy.mockRestore();
+ });
+
+ test('renders component with default props', () => {
+ render(
+ ,
+ );
+
+ expect(screen.getByText('$testVariable')).toBeInTheDocument();
+ });
+
+ test('renders Input when the variable type is TEXTBOX', () => {
+ render(
+ ,
+ );
+ expect(screen.getByPlaceholderText('Enter value')).toBeInTheDocument();
+ });
+
+ test('calls onChange event handler when Input value changes', () => {
+ render(
+ ,
+ );
+ const inputElement = screen.getByPlaceholderText('Enter value');
+ fireEvent.change(inputElement, { target: { value: 'newValue' } });
+
+ expect(mockOnValueUpdate).toHaveBeenCalledTimes(1);
+ expect(mockOnValueUpdate).toHaveBeenCalledWith('testVariable', 'newValue');
+ expect(mockOnAllSelectedUpdate).toHaveBeenCalledTimes(1);
+ expect(mockOnAllSelectedUpdate).toHaveBeenCalledWith('testVariable', false);
+ });
+
+ test('renders a Select element when variable type is CUSTOM', () => {
+ render(
+ ,
+ );
+
+ expect(screen.getByText('$customVariable')).toBeInTheDocument();
+ expect(screen.getByTestId('variable-select')).toBeInTheDocument();
+ });
+
+ test('renders a Select element with all selected', async () => {
+ const customVariableData = {
+ ...mockCustomVariableData,
+ allSelected: true,
+ };
+
+ render(
+ ,
+ );
+
+ expect(screen.getByTitle('ALL')).toBeInTheDocument();
+ });
+
+ test('calls useEffect when the component mounts', () => {
+ render(
+ ,
+ );
+
+ expect(React.useEffect).toHaveBeenCalled();
+ });
+
+ test('calls useEffect only once when the component mounts', () => {
+ // Render the component
+ const { rerender } = render(
+ ,
+ );
+
+ // Create an updated version of the mock data
+ const updatedMockCustomVariableData = {
+ ...mockCustomVariableData,
+ selectedValue: 'option1',
+ };
+
+ // Re-render the component with the updated data
+ rerender(
+ ,
+ );
+
+ // Check if the useEffect is called with the correct arguments
+ expect(useEffectSpy).toHaveBeenCalledTimes(4);
+ });
+});
diff --git a/frontend/src/container/NewDashboard/DashboardVariablesSelection/VariableItem.tsx b/frontend/src/container/NewDashboard/DashboardVariablesSelection/VariableItem.tsx
index 0aa6e61b90..a20e60f1a5 100644
--- a/frontend/src/container/NewDashboard/DashboardVariablesSelection/VariableItem.tsx
+++ b/frontend/src/container/NewDashboard/DashboardVariablesSelection/VariableItem.tsx
@@ -4,7 +4,7 @@ import { Input, Popover, Select, Typography } from 'antd';
import query from 'api/dashboard/variables/query';
import { commaValuesParser } from 'lib/dashbaordVariables/customCommaValuesParser';
import sortValues from 'lib/dashbaordVariables/sortVariableValues';
-import { map } from 'lodash-es';
+import map from 'lodash-es/map';
import React, { memo, useCallback, useEffect, useState } from 'react';
import { IDashboardVariable } from 'types/api/dashboard/getAll';
@@ -12,24 +12,16 @@ import { variablePropsToPayloadVariables } from '../utils';
import { SelectItemStyle, VariableContainer, VariableName } from './styles';
import { areArraysEqual } from './util';
-const { Option } = Select;
-
const ALL_SELECT_VALUE = '__ALL__';
interface VariableItemProps {
variableData: IDashboardVariable;
existingVariables: Record;
onValueUpdate: (
- name: string | undefined,
- arg1:
- | string
- | number
- | boolean
- | (string | number | boolean)[]
- | null
- | undefined,
+ name: string,
+ arg1: IDashboardVariable['selectedValue'],
) => void;
- onAllSelectedUpdate: (name: string | undefined, arg1: boolean) => void;
+ onAllSelectedUpdate: (name: string, arg1: boolean) => void;
lastUpdatedVar: string;
}
function VariableItem({
@@ -101,8 +93,10 @@ function VariableItem({
} else {
[value] = newOptionsData;
}
- onValueUpdate(variableData.name, value);
- onAllSelectedUpdate(variableData.name, allSelected);
+ if (variableData.name) {
+ onValueUpdate(variableData.name, value);
+ onAllSelectedUpdate(variableData.name, allSelected);
+ }
}
setOptionsData(newOptionsData);
}
@@ -133,17 +127,18 @@ function VariableItem({
}, [variableData, existingVariables]);
const handleChange = (value: string | string[]): void => {
- if (
- value === ALL_SELECT_VALUE ||
- (Array.isArray(value) && value.includes(ALL_SELECT_VALUE)) ||
- (Array.isArray(value) && value.length === 0)
- ) {
- onValueUpdate(variableData.name, optionsData);
- onAllSelectedUpdate(variableData.name, true);
- } else {
- onValueUpdate(variableData.name, value);
- onAllSelectedUpdate(variableData.name, false);
- }
+ if (variableData.name)
+ if (
+ value === ALL_SELECT_VALUE ||
+ (Array.isArray(value) && value.includes(ALL_SELECT_VALUE)) ||
+ (Array.isArray(value) && value.length === 0)
+ ) {
+ onValueUpdate(variableData.name, optionsData);
+ onAllSelectedUpdate(variableData.name, true);
+ } else {
+ onValueUpdate(variableData.name, value);
+ onAllSelectedUpdate(variableData.name, false);
+ }
};
const selectValue = variableData.allSelected
@@ -182,10 +177,21 @@ function VariableItem({
style={SelectItemStyle}
loading={isLoading}
showArrow
+ data-testid="variable-select"
>
- {enableSelectAll && }
+ {enableSelectAll && (
+
+ ALL
+
+ )}
{map(optionsData, (option) => (
-
+
+ {option.toString()}
+
))}
)
diff --git a/frontend/src/container/NewDashboard/DashboardVariablesSelection/utils.test.ts b/frontend/src/container/NewDashboard/DashboardVariablesSelection/utils.test.ts
new file mode 100644
index 0000000000..c258849a74
--- /dev/null
+++ b/frontend/src/container/NewDashboard/DashboardVariablesSelection/utils.test.ts
@@ -0,0 +1,33 @@
+import { areArraysEqual } from './util';
+
+describe('areArraysEqual', () => {
+ it('should return true for equal arrays with same order', () => {
+ const array1 = [1, 'a', true, 5, 'hello'];
+ const array2 = [1, 'a', true, 5, 'hello'];
+ expect(areArraysEqual(array1, array2)).toBe(true);
+ });
+
+ it('should return false for equal arrays with different order', () => {
+ const array1 = [1, 'a', true, 5, 'hello'];
+ const array2 = ['hello', 1, true, 'a', 5];
+ expect(areArraysEqual(array1, array2)).toBe(false);
+ });
+
+ it('should return false for arrays with different lengths', () => {
+ const array1 = [1, 'a', true, 5, 'hello'];
+ const array2 = [1, 'a', true, 5];
+ expect(areArraysEqual(array1, array2)).toBe(false);
+ });
+
+ it('should return false for arrays with different elements', () => {
+ const array1 = [1, 'a', true, 5, 'hello'];
+ const array2 = [1, 'a', true, 5, 'world'];
+ expect(areArraysEqual(array1, array2)).toBe(false);
+ });
+
+ it('should return true for empty arrays', () => {
+ const array1: string[] = [];
+ const array2: string[] = [];
+ expect(areArraysEqual(array1, array2)).toBe(true);
+ });
+});