/**
* Component: Indexer Management Tests
* Documentation: documentation/frontend/components.md
*/
// @vitest-environment jsdom
import { afterEach, describe, expect, it, vi } from 'vitest';
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import { IndexerManagement } from '@/components/admin/indexers/IndexerManagement';
const fetchWithAuthMock = vi.hoisted(() => vi.fn());
vi.mock('@/lib/utils/api', () => ({
fetchWithAuth: fetchWithAuthMock,
}));
vi.mock('@/components/admin/indexers/IndexerConfigModal', () => ({
IndexerConfigModal: ({ isOpen, mode, indexer, initialConfig, onSave, onClose }: any) => {
if (!isOpen) return null;
const priority = initialConfig?.priority ? initialConfig.priority + 1 : 10;
return (
{mode}
);
},
}));
describe('IndexerManagement', () => {
const emptyIndexers: any[] = [];
afterEach(() => {
vi.unstubAllGlobals();
fetchWithAuthMock.mockReset();
});
it('fetches indexers in wizard mode and adds a configuration', async () => {
const fetchMock = vi.fn().mockResolvedValue({
ok: true,
json: async () => ({
success: true,
indexers: [
{ id: 1, name: 'IndexerA', protocol: 'torrent', supportsRss: true },
],
}),
});
vi.stubGlobal('fetch', fetchMock);
const onIndexersChange = vi.fn();
render(
);
fireEvent.click(screen.getByRole('button', { name: 'Fetch Indexers' }));
await waitFor(() => {
expect(fetchMock).toHaveBeenCalledWith('/api/setup/test-prowlarr', expect.any(Object));
});
expect(fetchWithAuthMock).not.toHaveBeenCalled();
expect(screen.getByText('IndexerA')).toBeInTheDocument();
fireEvent.click(screen.getByRole('button', { name: 'Add' }));
fireEvent.click(screen.getByRole('button', { name: 'Save' }));
await waitFor(() => {
const lastCall = onIndexersChange.mock.calls.at(-1)?.[0] as any[] | undefined;
expect(lastCall).toHaveLength(1);
expect(lastCall?.[0]).toMatchObject({ id: 1, name: 'IndexerA' });
});
expect(screen.getByText('Configured Indexers (1)')).toBeInTheDocument();
});
it('uses authenticated fetch in settings mode', async () => {
const fetchMock = vi.fn();
vi.stubGlobal('fetch', fetchMock);
fetchWithAuthMock.mockResolvedValue({
ok: true,
json: async () => ({
success: true,
indexers: [
{ id: 2, name: 'IndexerB', protocol: 'torrent', supportsRss: false },
],
}),
});
render(
);
fireEvent.click(screen.getByRole('button', { name: 'Fetch Indexers' }));
await waitFor(() => {
expect(fetchWithAuthMock).toHaveBeenCalledWith(
'/api/admin/settings/test-prowlarr',
expect.objectContaining({ method: 'POST' })
);
});
expect(fetchMock).not.toHaveBeenCalled();
expect(screen.getByText('IndexerB')).toBeInTheDocument();
});
it('removes a configured indexer after confirmation', async () => {
const onIndexersChange = vi.fn();
render(
);
fireEvent.click(screen.getByTitle('Delete indexer'));
fireEvent.click(screen.getByRole('button', { name: 'Remove Indexer' }));
await waitFor(() => {
const lastCall = onIndexersChange.mock.calls.at(-1)?.[0] as any[] | undefined;
expect(lastCall).toHaveLength(0);
});
expect(screen.getByText('Configured Indexers (0)')).toBeInTheDocument();
});
});