signoz/frontend/src/container/PipelinePage/tests/AddNewProcessor.test.tsx
Shaheer Kochai ddb08b3883
feat: add support for JSON flattening in pipeline processor create and edit (#8331)
* feat: add support for JSON flattening in pipeline processor create and edit

* chore: add fallback value for mapping state

* feat: improve the UI of json flattening form and show path_prefix if enable_path is true

* fix: improve the state management

* chore: get enablePaths state using useWatch

* chore: json flattening tests

* chore: improve the test descriptions

* fix: update snapshot and adjust the existing failing test

* chore: overall improvements

* fix: update the JSON flattening keys map

* fix: destroy the new processor modal on closing to fix the unintended persistent mapping state

* chore: log event on saving pipeline if json_parser processors get modified

* chore: fix the alignment of json flattening switch

* chore: overall improvement

* refactor: improve the mapping comparison by using lodash's isEqual

* chore: update the snapshot

* refactor: improve the pipeline json_parser processor filtering logic

---------

Co-authored-by: Aditya Singh <adityasinghssj1@gmail.com>
Co-authored-by: Nityananda Gohain <nityanandagohain@gmail.com>
2025-07-14 06:04:04 +00:00

258 lines
7.7 KiB
TypeScript

import { fireEvent, screen, waitFor } from '@testing-library/react';
import { render as customRender } from 'tests/test-utils';
import { ProcessorData } from 'types/api/pipeline/def';
import { pipelineMockData } from '../mocks/pipeline';
import AddNewProcessor from '../PipelineListsView/AddNewProcessor';
// Mock the config module to set JSON parser as default
jest.mock('../PipelineListsView/AddNewProcessor/config', () => ({
...jest.requireActual('../PipelineListsView/AddNewProcessor/config'),
DEFAULT_PROCESSOR_TYPE: 'json_parser',
}));
jest.mock('uplot', () => {
const paths = {
spline: jest.fn(),
bars: jest.fn(),
};
const uplotMock = jest.fn(() => ({
paths,
}));
return {
paths,
default: uplotMock,
};
});
const selectedProcessorData = {
id: '1',
orderId: 1,
type: 'json_parser',
name: 'json parser',
output: 'jsonparser',
};
// Constants for repeated text
const ENABLE_PATHS_TEXT = 'Enable Paths';
const ENABLE_MAPPING_TEXT = 'Enable Mapping';
const PATH_PREFIX_LABEL = 'Path Prefix';
// Helper function to render AddNewProcessor with JSON parser type
const renderJsonProcessor = ({
selectedProcessorData: processorData = selectedProcessorData,
isActionType = 'add-processor',
}: {
selectedProcessorData?: ProcessorData;
isActionType?: 'add-processor' | 'edit-processor';
}): ReturnType<typeof customRender> => {
const defaultProps = {
isActionType,
setActionType: jest.fn(),
selectedProcessorData: processorData,
setShowSaveButton: jest.fn(),
expandedPipelineData: pipelineMockData[2],
setExpandedPipelineData: jest.fn(),
};
// eslint-disable-next-line react/jsx-props-no-spreading
return customRender(<AddNewProcessor {...defaultProps} />);
};
describe('JSON Flattening Processor Tests', () => {
describe('Enable/Disable Flattening', () => {
it('should display the form when enable flattening is turned on', async () => {
renderJsonProcessor({
selectedProcessorData: {
...selectedProcessorData,
enable_flattening: true,
},
});
// Verify the JSON flattening form is displayed
expect(screen.queryByText(ENABLE_PATHS_TEXT)).toBeInTheDocument();
expect(screen.queryByText(ENABLE_MAPPING_TEXT)).toBeInTheDocument();
});
it('should not display the form when enable flattening is turned off', async () => {
renderJsonProcessor({
selectedProcessorData: {
...selectedProcessorData,
enable_flattening: false,
},
});
// Verify the JSON flattening form is not displayed
expect(screen.queryByText(ENABLE_PATHS_TEXT)).not.toBeInTheDocument();
expect(screen.queryByText(ENABLE_MAPPING_TEXT)).not.toBeInTheDocument();
});
it('should display the form when enable flattening switch is toggled on', async () => {
renderJsonProcessor({});
// Wait for the component to render and find the enable flattening switch
await waitFor(() => {
expect(screen.getByRole('switch')).toBeInTheDocument();
});
// Find the enable flattening switch
const enableFlatteningSwitch = screen.getByRole('switch');
// Turn on the switch
fireEvent.click(enableFlatteningSwitch);
// Verify the JSON flattening form is displayed
await waitFor(() => {
expect(screen.getByText(ENABLE_PATHS_TEXT)).toBeInTheDocument();
expect(screen.getByText(ENABLE_MAPPING_TEXT)).toBeInTheDocument();
});
});
it('should hide the form when enable flattening switch is toggled off', async () => {
renderJsonProcessor({
selectedProcessorData: {
...selectedProcessorData,
enable_flattening: true,
},
});
// Wait for the component to render and find the switches
await waitFor(() => {
expect(screen.getAllByRole('switch')[0]).toBeInTheDocument();
});
// Find the enable flattening switch
const enableFlatteningSwitch = screen.getAllByRole('switch')[0];
// Turn off the switch
fireEvent.click(enableFlatteningSwitch);
await waitFor(() => {
expect(screen.queryByText(ENABLE_PATHS_TEXT)).not.toBeInTheDocument();
expect(screen.queryByText(ENABLE_MAPPING_TEXT)).not.toBeInTheDocument();
});
});
});
describe('Enable/Disable Paths', () => {
it('should toggle path prefix visibility when enable paths switch is toggled', async () => {
renderJsonProcessor({
selectedProcessorData: {
...selectedProcessorData,
enable_flattening: true,
enable_paths: false,
},
});
// Wait for the component to render and find the switches
await waitFor(() => {
expect(screen.getAllByRole('switch')[1]).toBeInTheDocument();
});
// In add mode, enable_paths is always true initially, so the path prefix should be visible
await waitFor(() => {
expect(screen.getByLabelText(PATH_PREFIX_LABEL)).toBeInTheDocument();
});
// Find the enable paths switch (second switch in the form) and turn it off
const enablePathsSwitch = screen.getAllByRole('switch')[1];
fireEvent.click(enablePathsSwitch);
// Verify the path prefix field is now hidden
await waitFor(() => {
expect(screen.queryByLabelText(PATH_PREFIX_LABEL)).not.toBeInTheDocument();
});
// Turn the paths switch back on
fireEvent.click(enablePathsSwitch);
// Verify the path prefix field is displayed again
await waitFor(() => {
expect(screen.getByLabelText(PATH_PREFIX_LABEL)).toBeInTheDocument();
});
});
it('should hide path prefix when enable paths switch is turned off', async () => {
renderJsonProcessor({
selectedProcessorData: {
...selectedProcessorData,
enable_flattening: true,
enable_paths: true,
},
});
// Wait for the component to render and find the switches
await waitFor(() => {
expect(screen.getAllByRole('switch')[1]).toBeInTheDocument();
});
// Verify the path prefix is initially visible
await waitFor(() => {
expect(screen.getByLabelText(PATH_PREFIX_LABEL)).toBeInTheDocument();
});
// Find the enable paths switch and turn it off
const enablePathsSwitch = screen.getAllByRole('switch')[1];
fireEvent.click(enablePathsSwitch);
// Verify the path prefix field is now hidden
await waitFor(() => {
expect(screen.queryByLabelText(PATH_PREFIX_LABEL)).not.toBeInTheDocument();
});
});
});
describe('Enable/Disable Mapping', () => {
it('should display the mapping fields when enable mapping is turned on', async () => {
renderJsonProcessor({
selectedProcessorData: {
...selectedProcessorData,
enable_flattening: true,
enable_paths: true,
mapping: {
environment: ['existing.env'],
host: ['existing.host'],
},
},
});
// Verify the mapping fields are displayed
await waitFor(() => {
expect(screen.getByText('environment')).toBeInTheDocument();
expect(screen.getByText('host')).toBeInTheDocument();
});
});
});
describe('Edit Processor Flow', () => {
it('should load existing processor data correctly when editing', async () => {
const existingProcessorData = {
id: '1',
orderId: 1,
type: 'json_parser',
name: 'test json parser',
output: 'testoutput',
enable_flattening: true,
enable_paths: true,
path_prefix: 'existing.prefix',
enable_mapping: true,
mapping: {
environment: ['existing.env'],
host: ['existing.host'],
},
};
renderJsonProcessor({
selectedProcessorData: existingProcessorData,
isActionType: 'edit-processor',
});
// Verify the form is displayed with existing data
await waitFor(() => {
expect(screen.getByDisplayValue('existing.prefix')).toBeInTheDocument();
});
// Verify flattening is enabled
const enableFlatteningSwitch = screen.getAllByRole('switch')[0];
expect(enableFlatteningSwitch).toBeChecked();
// Verify paths is enabled
const enablePathsSwitch = screen.getAllByRole('switch')[1];
expect(enablePathsSwitch).toBeChecked();
});
});
});