mod-arch-shared
Version:
Shared library for modular architecture micro-frontend projects
167 lines • 10.3 kB
JavaScript
import '@testing-library/jest-dom';
import * as React from 'react';
import { render, screen, act } from '@testing-library/react';
import useNamespaces from '../../hooks/useNamespaces';
import { useModularArchContext } from '../../hooks/useModularArchContext';
import { ModularArchContext } from '../../context/ModularArchContext';
import { NamespaceSelectorContext, NamespaceSelectorContextProvider, } from '../../context/NamespaceSelectorContext';
import { DeploymentMode, PlatformMode } from '../../utilities';
// Mock the hooks and utilities
jest.mock('~/hooks/useNamespaces');
jest.mock('~/hooks/useModularArchContext');
// jest.mock('~/utilities/const'); // Ensure this old mock is removed or commented out
const mockNamespaces = [{ name: 'namespace-2' }, { name: 'namespace-3' }, { name: 'namespace-1' }];
// Helper component to provide ModularArchContext
const MockModularArchContextProvider = ({ deploymentMode, platformMode, children }) => {
const mockContextValue = React.useMemo(() => ({
config: {
deploymentMode,
platformMode,
URL_PREFIX: 'model-registry',
BFF_API_VERSION: 'v1',
},
}), [deploymentMode, platformMode]);
// Mock the hook to return just the config, not the entire context
useModularArchContext.mockReturnValue(mockContextValue.config);
return (React.createElement(ModularArchContext.Provider, { value: mockContextValue }, children));
};
describe('NamespaceSelectorContext', () => {
const TestConsumer = () => {
const { namespaces, namespacesLoaded, namespacesLoadError, preferredNamespace, initializationError, } = React.useContext(NamespaceSelectorContext);
return (React.createElement("div", null,
React.createElement("div", { "data-testid": "loading-state" }, namespacesLoaded.toString()),
React.createElement("div", { "data-testid": "error-state" }, namespacesLoadError?.message || 'no-error'),
React.createElement("div", { "data-testid": "init-error" }, initializationError?.message || 'no-init-error'),
React.createElement("div", { "data-testid": "namespaces" }, namespaces.map((ns) => ns.name).join(',')),
React.createElement("div", { "data-testid": "preferred" }, preferredNamespace?.name || 'none')));
};
beforeEach(() => {
jest.clearAllMocks();
// Reset global window.centraldashboard
delete global.window.centraldashboard;
});
it('should provide initial empty state', () => {
useNamespaces.mockReturnValue([[], true, undefined]);
render(React.createElement(MockModularArchContextProvider, { deploymentMode: DeploymentMode.Standalone, platformMode: PlatformMode.Default },
React.createElement(NamespaceSelectorContextProvider, null,
React.createElement(TestConsumer, null))));
expect(screen.getByTestId('loading-state')).toHaveTextContent('true');
expect(screen.getByTestId('error-state')).toHaveTextContent('no-error');
expect(screen.getByTestId('namespaces')).toHaveTextContent('');
expect(screen.getByTestId('preferred')).toHaveTextContent('none');
});
it('should load namespaces and set first namespace as preferred when not integrated', () => {
useNamespaces.mockReturnValue([mockNamespaces, true, undefined]);
render(React.createElement(MockModularArchContextProvider, { deploymentMode: DeploymentMode.Standalone, platformMode: PlatformMode.Default },
React.createElement(NamespaceSelectorContextProvider, null,
React.createElement(TestConsumer, null))));
expect(screen.getByTestId('loading-state')).toHaveTextContent('true');
expect(screen.getByTestId('error-state')).toHaveTextContent('no-error');
expect(screen.getByTestId('namespaces')).toHaveTextContent('namespace-1,namespace-2,namespace-3');
expect(screen.getByTestId('preferred')).toHaveTextContent('namespace-1');
});
it('should handle errors during namespace loading', () => {
const error = new Error('Failed to load namespaces');
useNamespaces.mockReturnValue([[], true, error]);
render(React.createElement(MockModularArchContextProvider, { deploymentMode: DeploymentMode.Standalone, platformMode: PlatformMode.Default },
React.createElement(NamespaceSelectorContextProvider, null,
React.createElement(TestConsumer, null))));
expect(screen.getByTestId('loading-state')).toHaveTextContent('true');
expect(screen.getByTestId('error-state')).toHaveTextContent('Failed to load namespaces');
expect(screen.getByTestId('namespaces')).toHaveTextContent('');
expect(screen.getByTestId('preferred')).toHaveTextContent('none');
});
it('should initialize central dashboard client when integrated', () => {
useNamespaces.mockReturnValue([mockNamespaces, true, undefined]);
// Mock window.centraldashboard before rendering
const mockInit = jest.fn((callback) => {
// Simulate the callback being called
callback({
onNamespaceSelected: jest.fn(),
});
});
global.window.centraldashboard = {
CentralDashboardEventHandler: {
init: mockInit,
},
};
render(React.createElement(MockModularArchContextProvider, { deploymentMode: DeploymentMode.Integrated, platformMode: PlatformMode.Kubeflow },
React.createElement(NamespaceSelectorContextProvider, null,
React.createElement(TestConsumer, null))));
expect(mockInit).toHaveBeenCalled();
expect(screen.getByTestId('preferred')).toHaveTextContent('namespace-1');
});
it('should update preferred namespace when selected', () => {
useNamespaces.mockReturnValue([mockNamespaces, true, undefined]);
const TestUpdater = () => {
const { updatePreferredNamespace } = React.useContext(NamespaceSelectorContext);
React.useEffect(() => {
act(() => {
updatePreferredNamespace({ name: 'namespace-2' });
});
}, [updatePreferredNamespace]);
return null;
};
render(React.createElement(MockModularArchContextProvider, { deploymentMode: DeploymentMode.Standalone, platformMode: PlatformMode.Default },
React.createElement(NamespaceSelectorContextProvider, null,
React.createElement(TestConsumer, null),
React.createElement(TestUpdater, null))));
expect(screen.getByTestId('preferred')).toHaveTextContent('namespace-2');
});
it('should handle central dashboard initialization failure gracefully', () => {
useNamespaces.mockReturnValue([mockNamespaces, true, undefined]);
// Mock console.error to avoid test output noise
const consoleSpy = jest.spyOn(console, 'error').mockImplementation();
// Mock window.centraldashboard with an init function that throws an error BEFORE rendering
const error = new Error('Central dashboard initialization failed');
global.window.centraldashboard = {
CentralDashboardEventHandler: {
init: () => {
throw error;
},
},
};
render(React.createElement(MockModularArchContextProvider, { deploymentMode: DeploymentMode.Integrated, platformMode: PlatformMode.Kubeflow },
React.createElement(NamespaceSelectorContextProvider, null,
React.createElement(TestConsumer, null))));
expect(consoleSpy).toHaveBeenCalledWith('Failed to initialize central dashboard client', error);
expect(screen.getByTestId('init-error')).toHaveTextContent('Central dashboard initialization failed');
expect(screen.getByTestId('preferred')).toHaveTextContent('namespace-1');
consoleSpy.mockRestore();
});
it('should reflect loading state changes', async () => {
// Start with loading state
useNamespaces.mockReturnValue([[], false, undefined]);
const { rerender } = render(React.createElement(MockModularArchContextProvider, { deploymentMode: DeploymentMode.Standalone, platformMode: PlatformMode.Default },
React.createElement(NamespaceSelectorContextProvider, null,
React.createElement(TestConsumer, null))));
expect(screen.getByTestId('loading-state')).toHaveTextContent('false');
// Update to loaded state
useNamespaces.mockReturnValue([mockNamespaces, true, undefined]);
rerender(React.createElement(MockModularArchContextProvider, { deploymentMode: DeploymentMode.Standalone, platformMode: PlatformMode.Default },
React.createElement(NamespaceSelectorContextProvider, null,
React.createElement(TestConsumer, null))));
expect(screen.getByTestId('loading-state')).toHaveTextContent('true');
expect(screen.getByTestId('namespaces')).toHaveTextContent('namespace-1,namespace-2,namespace-3');
});
it('should handle multiple namespace updates correctly', () => {
useNamespaces.mockReturnValue([mockNamespaces, true, undefined]);
const TestMultipleUpdates = () => {
const { updatePreferredNamespace } = React.useContext(NamespaceSelectorContext);
React.useEffect(() => {
act(() => {
updatePreferredNamespace({ name: 'namespace-2' });
updatePreferredNamespace({ name: 'namespace-3' });
updatePreferredNamespace({ name: 'namespace-1' });
});
}, [updatePreferredNamespace]);
return null;
};
render(React.createElement(MockModularArchContextProvider, { deploymentMode: DeploymentMode.Standalone, platformMode: PlatformMode.Default },
React.createElement(NamespaceSelectorContextProvider, null,
React.createElement(TestConsumer, null),
React.createElement(TestMultipleUpdates, null))));
expect(screen.getByTestId('preferred')).toHaveTextContent('namespace-1');
});
});
//# sourceMappingURL=NamespaceSelectorContext.test.js.map