From 34cd2c1b407b62764812514003d235f57821354a Mon Sep 17 00:00:00 2001 From: sawhil Date: Mon, 19 May 2025 06:39:46 +0530 Subject: [PATCH] feat: added tests for preferences framework alongside some minor bugs improvements --- .../PreferenceContextProvider.test.tsx | 150 +++++++++++ .../__tests__/logsLoaderConfig.test.ts | 162 +++++++++++ .../__tests__/logsUpdaterConfig.test.ts | 251 ++++++++++++++++++ .../__tests__/usePreferenceLoader.test.tsx | 139 ++++++++++ .../__tests__/usePreferenceUpdater.test.tsx | 212 +++++++++++++++ .../preferences/sync/usePreferenceSync.ts | 4 - 6 files changed, 914 insertions(+), 4 deletions(-) create mode 100644 frontend/src/providers/preferences/__tests__/PreferenceContextProvider.test.tsx create mode 100644 frontend/src/providers/preferences/__tests__/logsLoaderConfig.test.ts create mode 100644 frontend/src/providers/preferences/__tests__/logsUpdaterConfig.test.ts create mode 100644 frontend/src/providers/preferences/__tests__/usePreferenceLoader.test.tsx create mode 100644 frontend/src/providers/preferences/__tests__/usePreferenceUpdater.test.tsx diff --git a/frontend/src/providers/preferences/__tests__/PreferenceContextProvider.test.tsx b/frontend/src/providers/preferences/__tests__/PreferenceContextProvider.test.tsx new file mode 100644 index 0000000000..2f5d4eab4f --- /dev/null +++ b/frontend/src/providers/preferences/__tests__/PreferenceContextProvider.test.tsx @@ -0,0 +1,150 @@ +/* eslint-disable sonarjs/no-identical-functions */ +import { render, screen } from '@testing-library/react'; +import { FormattingOptions, Preferences } from 'providers/preferences/types'; +import { MemoryRouter, Route, Switch } from 'react-router-dom'; +import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse'; + +import { + PreferenceContextProvider, + usePreferenceContext, +} from '../context/PreferenceContextProvider'; + +// Mock the usePreferenceSync hook +jest.mock('../sync/usePreferenceSync', () => ({ + usePreferenceSync: jest.fn().mockReturnValue({ + preferences: { + columns: [] as BaseAutocompleteData[], + formatting: { + maxLines: 2, + format: 'table', + fontSize: 'small', + version: 1, + } as FormattingOptions, + } as Preferences, + loading: false, + error: null, + updateColumns: jest.fn(), + updateFormatting: jest.fn(), + }), +})); + +// Test component that consumes the context +function TestConsumer(): JSX.Element { + const context = usePreferenceContext(); + return ( +
+
{context.mode}
+
{context.dataSource}
+
{String(context.loading)}
+
{String(context.error)}
+
{context.savedViewId || 'no-view-id'}
+
+ ); +} + +describe('PreferenceContextProvider', () => { + it('should provide context with direct mode when no viewKey is present', () => { + render( + + + ( + + + + )} + /> + + , + ); + + expect(screen.getByTestId('mode')).toHaveTextContent('direct'); + expect(screen.getByTestId('dataSource')).toHaveTextContent('logs'); + expect(screen.getByTestId('loading')).toHaveTextContent('false'); + expect(screen.getByTestId('error')).toHaveTextContent('null'); + expect(screen.getByTestId('savedViewId')).toHaveTextContent('no-view-id'); + }); + + it('should provide context with savedView mode when viewKey is present', () => { + render( + + + ( + + + + )} + /> + + , + ); + + expect(screen.getByTestId('mode')).toHaveTextContent('savedView'); + expect(screen.getByTestId('dataSource')).toHaveTextContent('logs'); + expect(screen.getByTestId('savedViewId')).toHaveTextContent('test-view-id'); + }); + + it('should set traces dataSource when pathname includes traces', () => { + render( + + + ( + + + + )} + /> + + , + ); + + expect(screen.getByTestId('dataSource')).toHaveTextContent('traces'); + }); + + it('should handle invalid viewKey JSON gracefully', () => { + // Mock console.error to avoid test output clutter + const originalConsoleError = console.error; + console.error = jest.fn(); + + render( + + + ( + + + + )} + /> + + , + ); + + expect(screen.getByTestId('mode')).toHaveTextContent('direct'); + expect(console.error).toHaveBeenCalled(); + + // Restore console.error + console.error = originalConsoleError; + }); + + it('should throw error when usePreferenceContext is used outside provider', () => { + // Suppress the error output for this test + const originalConsoleError = console.error; + console.error = jest.fn(); + + expect(() => { + render(); + }).toThrow( + 'usePreferenceContext must be used within PreferenceContextProvider', + ); + + // Restore console.error + console.error = originalConsoleError; + }); +}); diff --git a/frontend/src/providers/preferences/__tests__/logsLoaderConfig.test.ts b/frontend/src/providers/preferences/__tests__/logsLoaderConfig.test.ts new file mode 100644 index 0000000000..b6ab1b18af --- /dev/null +++ b/frontend/src/providers/preferences/__tests__/logsLoaderConfig.test.ts @@ -0,0 +1,162 @@ +import { LOCALSTORAGE } from 'constants/localStorage'; +import { LogViewMode } from 'container/LogsTable'; +import { defaultLogsSelectedColumns } from 'container/OptionsMenu/constants'; +import { FontSize } from 'container/OptionsMenu/types'; +import { FormattingOptions } from 'providers/preferences/types'; +import { + BaseAutocompleteData, + DataTypes, +} from 'types/api/queryBuilder/queryAutocompleteResponse'; + +import logsLoaderConfig from '../configs/logsLoaderConfig'; + +// Mock localStorage +const mockLocalStorage: Record = {}; + +jest.mock('api/browser/localstorage/get', () => ({ + __esModule: true, + default: jest.fn((key: string) => mockLocalStorage[key] || null), +})); + +describe('logsLoaderConfig', () => { + // Save original location object + const originalWindowLocation = window.location; + let mockedLocation: Partial; + + beforeEach(() => { + // Setup a mocked location object + mockedLocation = { + ...originalWindowLocation, + search: '', + }; + + // Mock the window.location property + Object.defineProperty(window, 'location', { + configurable: true, + value: mockedLocation, + writable: true, + }); + + // Clear mocked localStorage + Object.keys(mockLocalStorage).forEach((key) => { + delete mockLocalStorage[key]; + }); + }); + + afterEach(() => { + // Restore original location + Object.defineProperty(window, 'location', { + configurable: true, + value: originalWindowLocation, + writable: true, + }); + }); + + it('should have priority order: local, url, default', () => { + expect(logsLoaderConfig.priority).toEqual(['local', 'url', 'default']); + }); + + it('should load from localStorage when available', async () => { + const mockColumns: BaseAutocompleteData[] = [ + { + key: 'test-column', + type: 'tag', + dataType: DataTypes.String, + isColumn: true, + }, + ]; + + // Set up localStorage mock data with the correct key from LOCALSTORAGE enum + mockLocalStorage[LOCALSTORAGE.LOGS_LIST_OPTIONS] = JSON.stringify({ + selectColumns: mockColumns, + maxLines: 10, + format: 'json', + fontSize: 'large', + version: 2, + }); + + const result = await logsLoaderConfig.local(); + + expect(result).toEqual({ + columns: mockColumns, + formatting: { + maxLines: 10, + format: 'json' as LogViewMode, + fontSize: 'large' as FontSize, + version: 2, + } as FormattingOptions, + }); + }); + + it('should handle invalid localStorage data gracefully', async () => { + // Set up invalid localStorage mock data + mockLocalStorage[LOCALSTORAGE.LOGS_LIST_OPTIONS] = 'invalid-json'; + + const result = await logsLoaderConfig.local(); + + expect(result).toEqual({ + columns: [] as BaseAutocompleteData[], + formatting: undefined, + }); + }); + + it('should load from URL when available', async () => { + const mockColumns: BaseAutocompleteData[] = [ + { + key: 'url-column', + type: 'tag', + dataType: DataTypes.String, + isColumn: true, + }, + ]; + + // Set up URL search params + mockedLocation.search = `?options=${encodeURIComponent( + JSON.stringify({ + selectColumns: mockColumns, + maxLines: 5, + format: 'raw', + fontSize: 'medium', + version: 1, + }), + )}`; + + const result = await logsLoaderConfig.url(); + + expect(result).toEqual({ + columns: mockColumns, + formatting: { + maxLines: 5, + format: 'raw' as LogViewMode, + fontSize: 'medium' as FontSize, + version: 1, + } as FormattingOptions, + }); + }); + + it('should handle invalid URL data gracefully', async () => { + // Set up invalid URL search params + mockedLocation.search = '?options=invalid-json'; + + const result = await logsLoaderConfig.url(); + + expect(result).toEqual({ + columns: [] as BaseAutocompleteData[], + formatting: undefined, + }); + }); + + it('should provide default values when no other source is available', async () => { + const result = await logsLoaderConfig.default(); + + expect(result).toEqual({ + columns: defaultLogsSelectedColumns as BaseAutocompleteData[], + formatting: { + maxLines: 2, + format: 'table' as LogViewMode, + fontSize: 'small' as FontSize, + version: 1, + } as FormattingOptions, + }); + }); +}); diff --git a/frontend/src/providers/preferences/__tests__/logsUpdaterConfig.test.ts b/frontend/src/providers/preferences/__tests__/logsUpdaterConfig.test.ts new file mode 100644 index 0000000000..20488c093e --- /dev/null +++ b/frontend/src/providers/preferences/__tests__/logsUpdaterConfig.test.ts @@ -0,0 +1,251 @@ +import { LOCALSTORAGE } from 'constants/localStorage'; +import { LogViewMode } from 'container/LogsTable'; +import { defaultOptionsQuery } from 'container/OptionsMenu/constants'; +import { FontSize } from 'container/OptionsMenu/types'; +import { FormattingOptions, PreferenceMode } from 'providers/preferences/types'; +import { + BaseAutocompleteData, + DataTypes, +} from 'types/api/queryBuilder/queryAutocompleteResponse'; + +import getLogsUpdaterConfig from '../configs/logsUpdaterConfig'; + +// Mock localStorage +const mockLocalStorage: Record = {}; + +jest.mock('api/browser/localstorage/set', () => ({ + __esModule: true, + default: jest.fn((key: string, value: string) => { + mockLocalStorage[key] = value; + }), +})); + +// Mock localStorage.getItem +Object.defineProperty(window, 'localStorage', { + value: { + getItem: jest.fn((key: string) => mockLocalStorage[key] || null), + setItem: jest.fn((key: string, value: string) => { + mockLocalStorage[key] = value; + }), + }, + writable: true, +}); + +describe('logsUpdaterConfig', () => { + // Mock redirectWithOptionsData and setSavedViewPreferences + const redirectWithOptionsData = jest.fn(); + const setSavedViewPreferences = jest.fn(); + + beforeEach(() => { + jest.clearAllMocks(); + // Clear mocked localStorage + Object.keys(mockLocalStorage).forEach((key) => { + delete mockLocalStorage[key]; + }); + }); + + it('should update columns in localStorage for direct mode', () => { + const logsUpdater = getLogsUpdaterConfig( + redirectWithOptionsData, + setSavedViewPreferences, + ); + + const newColumns: BaseAutocompleteData[] = [ + { + key: 'new-column', + type: 'tag', + dataType: DataTypes.String, + isColumn: true, + }, + ]; + + // Set initial localStorage data + mockLocalStorage[LOCALSTORAGE.LOGS_LIST_OPTIONS] = JSON.stringify({ + selectColumns: [ + { + key: 'old-column', + type: 'tag', + dataType: DataTypes.String, + isColumn: true, + }, + ], + maxLines: 2, + }); + + logsUpdater.updateColumns(newColumns, 'direct' as PreferenceMode); + + // Should update URL + expect(redirectWithOptionsData).toHaveBeenCalledWith({ + ...defaultOptionsQuery, + selectColumns: newColumns, + }); + + // Should update localStorage + const storedData = JSON.parse( + mockLocalStorage[LOCALSTORAGE.LOGS_LIST_OPTIONS], + ); + expect(storedData.selectColumns).toEqual(newColumns); + expect(storedData.maxLines).toBe(2); // Should preserve other fields + + // Should not update saved view preferences + expect(setSavedViewPreferences).not.toHaveBeenCalled(); + }); + + it('should update columns in savedViewPreferences for savedView mode', () => { + const logsUpdater = getLogsUpdaterConfig( + redirectWithOptionsData, + setSavedViewPreferences, + ); + + const newColumns: BaseAutocompleteData[] = [ + { + key: 'new-column', + type: 'tag', + dataType: DataTypes.String, + isColumn: true, + }, + ]; + + logsUpdater.updateColumns(newColumns, 'savedView' as PreferenceMode); + + // Should not update URL in savedView mode + expect(redirectWithOptionsData).not.toHaveBeenCalled(); + + // Should not update localStorage in savedView mode + expect(mockLocalStorage[LOCALSTORAGE.LOGS_LIST_OPTIONS]).toBeUndefined(); + + // Should update saved view preferences + expect(setSavedViewPreferences).toHaveBeenCalledWith({ + columns: newColumns, + formatting: { + maxLines: 2, + format: 'table', + fontSize: 'small', + version: 1, + }, + }); + }); + + it('should update formatting options in localStorage for direct mode', () => { + const logsUpdater = getLogsUpdaterConfig( + redirectWithOptionsData, + setSavedViewPreferences, + ); + + const newFormatting: FormattingOptions = { + maxLines: 5, + format: 'json' as LogViewMode, + fontSize: 'large' as FontSize, + version: 1, + }; + + // Set initial localStorage data + mockLocalStorage[LOCALSTORAGE.LOGS_LIST_OPTIONS] = JSON.stringify({ + selectColumns: [ + { + key: 'column', + type: 'tag', + dataType: DataTypes.String, + isColumn: true, + }, + ], + maxLines: 2, + format: 'table', + }); + + logsUpdater.updateFormatting(newFormatting, 'direct' as PreferenceMode); + + // Should always update URL for both modes + expect(redirectWithOptionsData).toHaveBeenCalledWith({ + ...defaultOptionsQuery, + ...newFormatting, + }); + + // Should update localStorage in direct mode + const storedData = JSON.parse( + mockLocalStorage[LOCALSTORAGE.LOGS_LIST_OPTIONS], + ); + expect(storedData.maxLines).toBe(5); + expect(storedData.format).toBe('json'); + expect(storedData.fontSize).toBe('large'); + expect(storedData.version).toBe(1); + expect(storedData.selectColumns).toEqual([ + { + key: 'column', + type: 'tag', + dataType: DataTypes.String, + isColumn: true, + }, + ]); // Should preserve columns + }); + + it('should not update localStorage for savedView mode in updateFormatting', () => { + const logsUpdater = getLogsUpdaterConfig( + redirectWithOptionsData, + setSavedViewPreferences, + ); + + const newFormatting: FormattingOptions = { + maxLines: 5, + format: 'json' as LogViewMode, + fontSize: 'large' as FontSize, + version: 1, + }; + + // Set initial localStorage data + mockLocalStorage[LOCALSTORAGE.LOGS_LIST_OPTIONS] = JSON.stringify({ + selectColumns: [ + { + key: 'column', + type: 'tag', + dataType: DataTypes.String, + isColumn: true, + }, + ], + maxLines: 2, + format: 'table', + }); + + logsUpdater.updateFormatting(newFormatting, 'savedView' as PreferenceMode); + + // Should always update URL for both modes + expect(redirectWithOptionsData).toHaveBeenCalledWith({ + ...defaultOptionsQuery, + ...newFormatting, + }); + + // Should not override localStorage in savedView mode + const storedData = JSON.parse( + mockLocalStorage[LOCALSTORAGE.LOGS_LIST_OPTIONS], + ); + expect(storedData.maxLines).toBe(2); // Should remain the same + expect(storedData.format).toBe('table'); // Should remain the same + }); + + it('should initialize localStorage if it does not exist', () => { + const logsUpdater = getLogsUpdaterConfig( + redirectWithOptionsData, + setSavedViewPreferences, + ); + + const newFormatting: FormattingOptions = { + maxLines: 5, + format: 'json' as LogViewMode, + fontSize: 'large' as FontSize, + version: 1, + }; + + // No initial localStorage data + + logsUpdater.updateFormatting(newFormatting, 'direct' as PreferenceMode); + + // Should create localStorage entry + const storedData = JSON.parse( + mockLocalStorage[LOCALSTORAGE.LOGS_LIST_OPTIONS], + ); + expect(storedData.maxLines).toBe(5); + expect(storedData.format).toBe('json'); + expect(storedData.fontSize).toBe('large'); + expect(storedData.version).toBe(1); + }); +}); diff --git a/frontend/src/providers/preferences/__tests__/usePreferenceLoader.test.tsx b/frontend/src/providers/preferences/__tests__/usePreferenceLoader.test.tsx new file mode 100644 index 0000000000..24b9af78b9 --- /dev/null +++ b/frontend/src/providers/preferences/__tests__/usePreferenceLoader.test.tsx @@ -0,0 +1,139 @@ +/* eslint-disable sonarjs/no-duplicate-string */ +import { renderHook, waitFor } from '@testing-library/react'; +import { DataSource } from 'types/common/queryBuilder'; + +import logsLoaderConfig from '../configs/logsLoaderConfig'; +import { usePreferenceLoader } from '../loader/usePreferenceLoader'; + +// Mock the config loaders +jest.mock('../configs/logsLoaderConfig', () => ({ + __esModule: true, + default: { + priority: ['local', 'url', 'default'], + local: jest.fn().mockResolvedValue({ + columns: [{ name: 'local-column' }], + formatting: { maxLines: 5, format: 'table', fontSize: 'medium', version: 1 }, + }), + url: jest.fn().mockResolvedValue({ + columns: [{ name: 'url-column' }], + formatting: { maxLines: 3, format: 'table', fontSize: 'small', version: 1 }, + }), + default: jest.fn().mockResolvedValue({ + columns: [{ name: 'default-column' }], + formatting: { maxLines: 2, format: 'table', fontSize: 'small', version: 1 }, + }), + }, +})); + +jest.mock('../configs/tracesLoaderConfig', () => ({ + __esModule: true, + default: { + priority: ['local', 'url', 'default'], + local: jest.fn().mockResolvedValue({ + columns: [{ name: 'local-trace-column' }], + }), + url: jest.fn().mockResolvedValue({ + columns: [{ name: 'url-trace-column' }], + }), + default: jest.fn().mockResolvedValue({ + columns: [{ name: 'default-trace-column' }], + }), + }, +})); + +describe('usePreferenceLoader', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should load logs preferences based on priority order', async () => { + const { result } = renderHook(() => + usePreferenceLoader({ dataSource: DataSource.LOGS, reSync: 0 }), + ); + + // Initially it should be loading + expect(result.current.loading).toBe(true); + expect(result.current.preferences).toBe(null); + expect(result.current.error).toBe(null); + + // Wait for the loader to complete + await waitFor(() => { + expect(result.current.loading).toBe(false); + }); + + // Should have loaded from local storage (highest priority) + expect(result.current.preferences).toEqual({ + columns: [{ name: 'local-column' }], + formatting: { maxLines: 5, format: 'table', fontSize: 'medium', version: 1 }, + }); + expect(result.current.error).toBe(null); + }); + + it('should load traces preferences', async () => { + const { result } = renderHook(() => + usePreferenceLoader({ dataSource: DataSource.TRACES, reSync: 0 }), + ); + + // Wait for the loader to complete + await waitFor(() => { + expect(result.current.loading).toBe(false); + }); + + // Should have loaded trace columns + expect(result.current.preferences).toEqual({ + columns: [{ name: 'local-trace-column' }], + }); + }); + + it('should re-load preferences when reSync changes', async () => { + const { result, rerender } = renderHook( + ({ dataSource, reSync }) => usePreferenceLoader({ dataSource, reSync }), + { initialProps: { dataSource: DataSource.LOGS, reSync: 0 } }, + ); + + // Wait for the first load to complete + await waitFor(() => { + expect(result.current.loading).toBe(false); + }); + + // Trigger a reSync + rerender({ dataSource: DataSource.LOGS, reSync: 1 }); + + // Should start loading again + expect(result.current.loading).toBe(true); + + // Wait for the second load to complete + await waitFor(() => { + expect(result.current.loading).toBe(false); + }); + + // Should have reloaded from local storage + expect(result.current.preferences).toEqual({ + columns: [{ name: 'local-column' }], + formatting: { maxLines: 5, format: 'table', fontSize: 'medium', version: 1 }, + }); + }); + + it('should handle errors during loading', async () => { + // Mock an error in the loader using jest.spyOn + const localSpy = jest.spyOn(logsLoaderConfig, 'local'); + localSpy.mockRejectedValueOnce(new Error('Loading failed')); + + const { result } = renderHook(() => + usePreferenceLoader({ dataSource: DataSource.LOGS, reSync: 0 }), + ); + + // Wait for the loader to complete + await waitFor(() => { + expect(result.current.loading).toBe(false); + }); + + // Should have set the error + expect(result.current.error).toBeInstanceOf(Error); + expect(result.current.error?.message).toBe('Loading failed'); + expect(result.current.preferences).toBe(null); + + // Restore original implementation + localSpy.mockRestore(); + }); +}); diff --git a/frontend/src/providers/preferences/__tests__/usePreferenceUpdater.test.tsx b/frontend/src/providers/preferences/__tests__/usePreferenceUpdater.test.tsx new file mode 100644 index 0000000000..fa29b94aa6 --- /dev/null +++ b/frontend/src/providers/preferences/__tests__/usePreferenceUpdater.test.tsx @@ -0,0 +1,212 @@ +/* eslint-disable sonarjs/no-identical-functions */ +import { renderHook } from '@testing-library/react'; +import { LogViewMode } from 'container/LogsTable'; +import { FontSize } from 'container/OptionsMenu/types'; +import { FormattingOptions, PreferenceMode } from 'providers/preferences/types'; +import { act } from 'react-dom/test-utils'; +import { + BaseAutocompleteData, + DataTypes, +} from 'types/api/queryBuilder/queryAutocompleteResponse'; +import { DataSource } from 'types/common/queryBuilder'; + +import { usePreferenceUpdater } from '../updater/usePreferenceUpdater'; + +// Mock the config updaters +const mockUpdateColumns = jest.fn(); +const mockUpdateFormatting = jest.fn(); + +jest.mock('../configs/logsUpdaterConfig', () => ({ + __esModule: true, + default: jest.fn().mockImplementation(() => ({ + updateColumns: mockUpdateColumns, + updateFormatting: mockUpdateFormatting, + })), +})); + +jest.mock('../configs/tracesUpdaterConfig', () => ({ + __esModule: true, + default: jest.fn().mockImplementation(() => ({ + updateColumns: mockUpdateColumns, + updateFormatting: mockUpdateFormatting, + })), +})); + +// Mock the URL query hook +jest.mock('hooks/useUrlQueryData', () => ({ + __esModule: true, + default: jest.fn().mockReturnValue({ + redirectWithQuery: jest.fn(), + }), +})); + +describe('usePreferenceUpdater', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should return updateColumns and updateFormatting functions', () => { + const setReSync = jest.fn(); + const setSavedViewPreferences = jest.fn(); + + const { result } = renderHook(() => + usePreferenceUpdater({ + dataSource: DataSource.LOGS, + mode: 'direct' as PreferenceMode, + setReSync, + setSavedViewPreferences, + }), + ); + + // Should return the update functions + expect(typeof result.current.updateColumns).toBe('function'); + expect(typeof result.current.updateFormatting).toBe('function'); + }); + + it('should call the logs updater for updateColumns with logs dataSource', () => { + const setReSync = jest.fn(); + const setSavedViewPreferences = jest.fn(); + const newColumns: BaseAutocompleteData[] = [ + { + key: 'new-column', + type: 'tag', + dataType: DataTypes.String, + isColumn: true, + }, + ]; + + const { result } = renderHook(() => + usePreferenceUpdater({ + dataSource: DataSource.LOGS, + mode: 'direct' as PreferenceMode, + setReSync, + setSavedViewPreferences, + }), + ); + + act(() => { + result.current.updateColumns(newColumns); + }); + + // Should call the logs updater + expect(mockUpdateColumns).toHaveBeenCalledWith(newColumns, 'direct'); + expect(setReSync).toHaveBeenCalled(); + }); + + it('should call the logs updater for updateFormatting with logs dataSource', () => { + const setReSync = jest.fn(); + const setSavedViewPreferences = jest.fn(); + const newFormatting: FormattingOptions = { + maxLines: 10, + format: 'table' as LogViewMode, + fontSize: 'large' as FontSize, + version: 1, + }; + + const { result } = renderHook(() => + usePreferenceUpdater({ + dataSource: DataSource.LOGS, + mode: 'direct' as PreferenceMode, + setReSync, + setSavedViewPreferences, + }), + ); + + act(() => { + result.current.updateFormatting(newFormatting); + }); + + // Should call the logs updater + expect(mockUpdateFormatting).toHaveBeenCalledWith(newFormatting, 'direct'); + expect(setReSync).toHaveBeenCalled(); + }); + + it('should call the traces updater for updateColumns with traces dataSource', () => { + const setReSync = jest.fn(); + const setSavedViewPreferences = jest.fn(); + const newColumns: BaseAutocompleteData[] = [ + { + key: 'new-trace-column', + type: 'tag', + dataType: DataTypes.String, + isColumn: true, + }, + ]; + + const { result } = renderHook(() => + usePreferenceUpdater({ + dataSource: DataSource.TRACES, + mode: 'direct' as PreferenceMode, + setReSync, + setSavedViewPreferences, + }), + ); + + act(() => { + result.current.updateColumns(newColumns); + }); + + // Should call the traces updater + expect(mockUpdateColumns).toHaveBeenCalledWith(newColumns, 'direct'); + expect(setReSync).toHaveBeenCalled(); + }); + + it('should call the traces updater for updateFormatting with traces dataSource', () => { + const setReSync = jest.fn(); + const setSavedViewPreferences = jest.fn(); + const newFormatting: FormattingOptions = { + maxLines: 10, + format: 'table' as LogViewMode, + fontSize: 'large' as FontSize, + version: 1, + }; + + const { result } = renderHook(() => + usePreferenceUpdater({ + dataSource: DataSource.TRACES, + mode: 'direct' as PreferenceMode, + setReSync, + setSavedViewPreferences, + }), + ); + + act(() => { + result.current.updateFormatting(newFormatting); + }); + + // Should call the traces updater + expect(mockUpdateFormatting).toHaveBeenCalledWith(newFormatting, 'direct'); + expect(setReSync).toHaveBeenCalled(); + }); + + it('should increment reSync counter when updates are called', () => { + const setReSync = jest.fn(); + const setSavedViewPreferences = jest.fn(); + + const { result } = renderHook(() => + usePreferenceUpdater({ + dataSource: DataSource.LOGS, + mode: 'direct' as PreferenceMode, + setReSync, + setSavedViewPreferences, + }), + ); + + act(() => { + result.current.updateColumns([ + { + key: 'column', + type: 'tag', + dataType: DataTypes.String, + isColumn: true, + }, + ]); + }); + + expect(setReSync).toHaveBeenCalledWith(expect.any(Function)); + + // Simulate the setReSync callback to ensure it increments + const incrementFn = setReSync.mock.calls[0][0]; + expect(incrementFn(1)).toBe(2); + }); +}); diff --git a/frontend/src/providers/preferences/sync/usePreferenceSync.ts b/frontend/src/providers/preferences/sync/usePreferenceSync.ts index 75908c6c56..4934d8df12 100644 --- a/frontend/src/providers/preferences/sync/usePreferenceSync.ts +++ b/frontend/src/providers/preferences/sync/usePreferenceSync.ts @@ -37,10 +37,6 @@ export function usePreferenceSync({ )?.extraData; const parsedExtraData = JSON.parse(extraData || '{}'); - console.log('uncaught extraData', { - extraData, - parsedExtraData, - }); let columns: BaseAutocompleteData[] = []; let formatting: FormattingOptions | undefined; if (dataSource === DataSource.LOGS) {