mirror of https://github.com/portainer/portainer
219 lines
6.4 KiB
TypeScript
219 lines
6.4 KiB
TypeScript
import { render, screen, fireEvent } from '@testing-library/react';
|
|
import userEvent from '@testing-library/user-event';
|
|
|
|
import { withTestQueryProvider } from '@/react/test-utils/withTestQuery';
|
|
import { withUserProvider } from '@/react/test-utils/withUserProvider';
|
|
import { withTestRouter } from '@/react/test-utils/withRouter';
|
|
import { UserViewModel } from '@/portainer/models/user';
|
|
|
|
import { Chart } from '../types';
|
|
|
|
import { HelmTemplatesList } from './HelmTemplatesList';
|
|
|
|
// Sample test data
|
|
const mockCharts: Chart[] = [
|
|
{
|
|
name: 'test-chart-1',
|
|
description: 'Test Chart 1 Description',
|
|
repo: 'https://example.com',
|
|
annotations: {
|
|
category: 'database',
|
|
},
|
|
version: '1.0.0',
|
|
versions: ['1.0.0', '1.0.1'],
|
|
},
|
|
{
|
|
name: 'test-chart-2',
|
|
description: 'Test Chart 2 Description',
|
|
repo: 'https://example.com',
|
|
annotations: {
|
|
category: 'database',
|
|
},
|
|
version: '1.0.0',
|
|
versions: ['1.0.0', '1.0.1'],
|
|
},
|
|
{
|
|
name: 'nginx-chart',
|
|
description: 'Nginx Web Server',
|
|
repo: 'https://example.com/2',
|
|
annotations: {
|
|
category: 'web',
|
|
},
|
|
version: '1.0.0',
|
|
versions: ['1.0.0', '1.0.1'],
|
|
},
|
|
];
|
|
|
|
const selectActionMock = vi.fn();
|
|
|
|
function renderComponent({
|
|
loading = false,
|
|
charts = mockCharts,
|
|
selectAction = selectActionMock,
|
|
selectedRegistry = '',
|
|
} = {}) {
|
|
const user = new UserViewModel({ Username: 'user' });
|
|
const registries = ['https://example.com', 'https://example.com/2'];
|
|
|
|
const Wrapped = withTestQueryProvider(
|
|
withUserProvider(
|
|
withTestRouter(() => (
|
|
<HelmTemplatesList
|
|
isLoading={loading}
|
|
charts={charts}
|
|
selectAction={selectAction}
|
|
registries={registries}
|
|
selectedRegistry={selectedRegistry}
|
|
setSelectedRegistry={() => {}}
|
|
/>
|
|
)),
|
|
user
|
|
)
|
|
);
|
|
return { ...render(<Wrapped />), user };
|
|
}
|
|
|
|
describe('HelmTemplatesList', () => {
|
|
beforeEach(() => {
|
|
selectActionMock.mockClear();
|
|
});
|
|
|
|
it('should display title and charts list', async () => {
|
|
renderComponent();
|
|
|
|
// Check for the title
|
|
expect(screen.getByText('Helm chart')).toBeInTheDocument();
|
|
|
|
// Check for charts
|
|
expect(screen.getByText('test-chart-1')).toBeInTheDocument();
|
|
expect(screen.getByText('Test Chart 1 Description')).toBeInTheDocument();
|
|
expect(screen.getByText('nginx-chart')).toBeInTheDocument();
|
|
expect(screen.getByText('Nginx Web Server')).toBeInTheDocument();
|
|
expect(screen.getByText('https://example.com/2')).toBeInTheDocument();
|
|
});
|
|
|
|
it('should call selectAction when a chart is clicked', async () => {
|
|
renderComponent();
|
|
|
|
// Find the first chart item
|
|
const firstChartItem = screen.getByText('test-chart-1').closest('button');
|
|
expect(firstChartItem).not.toBeNull();
|
|
|
|
// Click on the chart item
|
|
if (firstChartItem) {
|
|
fireEvent.click(firstChartItem);
|
|
}
|
|
|
|
// Check if selectAction was called with the correct chart
|
|
expect(selectActionMock).toHaveBeenCalledWith(mockCharts[0]);
|
|
});
|
|
|
|
it('should filter charts by text search', async () => {
|
|
renderComponent();
|
|
const user = userEvent.setup();
|
|
|
|
// Find search input and type "nginx"
|
|
const searchInput = screen.getByPlaceholderText('Search...');
|
|
await user.type(searchInput, 'nginx');
|
|
|
|
// Wait 300ms for debounce
|
|
await new Promise((resolve) => {
|
|
setTimeout(() => {
|
|
resolve(undefined);
|
|
}, 300);
|
|
});
|
|
|
|
// Should show only nginx chart
|
|
expect(screen.getByText('nginx-chart')).toBeInTheDocument();
|
|
expect(screen.queryByText('test-chart-1')).not.toBeInTheDocument();
|
|
expect(screen.queryByText('test-chart-2')).not.toBeInTheDocument();
|
|
});
|
|
|
|
it('should filter charts by category', async () => {
|
|
renderComponent();
|
|
const user = userEvent.setup();
|
|
|
|
// Find the category select
|
|
const categorySelect = screen.getByText('Select a category');
|
|
await user.click(categorySelect);
|
|
|
|
// Select "web" category
|
|
const webCategory = screen.getByText('web', {
|
|
selector: '[tabindex="-1"]',
|
|
});
|
|
await user.click(webCategory);
|
|
|
|
// Should show only web category charts
|
|
expect(screen.queryByText('nginx-chart')).toBeInTheDocument();
|
|
expect(screen.queryByText('test-chart-1')).not.toBeInTheDocument();
|
|
expect(screen.queryByText('test-chart-2')).not.toBeInTheDocument();
|
|
});
|
|
|
|
it('should show loading message when loading prop is true', async () => {
|
|
renderComponent({ loading: true, charts: [] });
|
|
|
|
// Check for loading message
|
|
expect(screen.getByText('Loading helm charts...')).toBeInTheDocument();
|
|
expect(
|
|
screen.getByText('Initial download of Helm charts can take a few minutes')
|
|
).toBeInTheDocument();
|
|
});
|
|
|
|
it('should show empty message when no charts are available and a registry is selected', async () => {
|
|
renderComponent({ charts: [], selectedRegistry: 'https://example.com' });
|
|
|
|
// Check for empty message
|
|
expect(
|
|
screen.getByText('No helm charts available in this registry.')
|
|
).toBeInTheDocument();
|
|
});
|
|
|
|
it("should show 'select registry' message when no charts are available and no registry is selected", async () => {
|
|
renderComponent({ charts: [] });
|
|
|
|
// Check for message
|
|
expect(
|
|
screen.getByText(
|
|
'Please select a registry to view available Helm charts.'
|
|
)
|
|
).toBeInTheDocument();
|
|
});
|
|
|
|
it('should show no results message when search has no matches', async () => {
|
|
renderComponent();
|
|
const user = userEvent.setup();
|
|
|
|
// Find search input and type text that won't match any charts
|
|
const searchInput = screen.getByPlaceholderText('Search...');
|
|
await user.type(searchInput, 'nonexistent chart');
|
|
|
|
// Wait 300ms for debounce
|
|
await new Promise((resolve) => {
|
|
setTimeout(() => {
|
|
resolve(undefined);
|
|
}, 300);
|
|
});
|
|
|
|
// Check for no results message
|
|
expect(screen.getByText('No Helm charts found')).toBeInTheDocument();
|
|
});
|
|
|
|
it('should handle keyboard navigation and selection', async () => {
|
|
renderComponent();
|
|
const user = userEvent.setup();
|
|
|
|
// Find the first chart item
|
|
const firstChartItem = screen.getByText('test-chart-1').closest('button');
|
|
expect(firstChartItem).not.toBeNull();
|
|
|
|
// Focus and press Enter
|
|
if (firstChartItem) {
|
|
(firstChartItem as HTMLElement).focus();
|
|
await user.keyboard('{Enter}');
|
|
}
|
|
|
|
// Check if selectAction was called with the correct chart
|
|
expect(selectActionMock).toHaveBeenCalledWith(mockCharts[0]);
|
|
});
|
|
});
|