mirror of
https://github.com/kikootwo/ReadMeABook.git
synced 2026-06-02 20:30:10 +00:00
d70f6c9957
Introduce Deluge download client service and tests, remove obsolete rdtclient service, and update qbittorrent integration/tests and download-client interfaces/manager. Large UI refactor for admin pages: Jobs and Logs were redesigned to be responsive (mobile card views + desktop tables), improved headers, dialogs, controls, and better status/detail rendering. Also updated DownloadClient components (card, management, modal), organize-files processor, audible-series integration, and related unit tests to align with integration changes. Minor UX and accessibility tweaks, cron handling/validation adjustments, and a few formatting/cleanup fixes throughout.
112 lines
3.3 KiB
TypeScript
112 lines
3.3 KiB
TypeScript
/**
|
|
* Component: Admin Jobs Page Tests
|
|
* Documentation: documentation/backend/services/scheduler.md
|
|
*/
|
|
|
|
// @vitest-environment jsdom
|
|
|
|
import React from 'react';
|
|
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
|
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
import AdminJobsPage from '@/app/admin/jobs/page';
|
|
|
|
const authenticatedFetcherMock = vi.hoisted(() => vi.fn());
|
|
const fetchJSONMock = vi.hoisted(() => vi.fn());
|
|
const toastMock = vi.hoisted(() => ({
|
|
success: vi.fn(),
|
|
error: vi.fn(),
|
|
info: vi.fn(),
|
|
warning: vi.fn(),
|
|
}));
|
|
|
|
vi.mock('@/lib/utils/api', () => ({
|
|
authenticatedFetcher: authenticatedFetcherMock,
|
|
fetchJSON: fetchJSONMock,
|
|
}));
|
|
|
|
vi.mock('@/components/ui/Toast', () => ({
|
|
ToastProvider: ({ children }: { children: React.ReactNode }) => <>{children}</>,
|
|
useToast: () => toastMock,
|
|
}));
|
|
|
|
describe('AdminJobsPage', () => {
|
|
beforeEach(() => {
|
|
authenticatedFetcherMock.mockReset();
|
|
fetchJSONMock.mockReset();
|
|
toastMock.success.mockReset();
|
|
toastMock.error.mockReset();
|
|
});
|
|
|
|
it('renders scheduled jobs and allows manual trigger', async () => {
|
|
authenticatedFetcherMock.mockResolvedValue({
|
|
jobs: [
|
|
{
|
|
id: 'job-1',
|
|
name: 'Library Scan',
|
|
type: 'scan_plex',
|
|
schedule: '0 * * * *',
|
|
enabled: true,
|
|
lastRun: null,
|
|
nextRun: null,
|
|
},
|
|
],
|
|
});
|
|
fetchJSONMock.mockResolvedValue({ success: true });
|
|
|
|
render(<AdminJobsPage />);
|
|
|
|
expect((await screen.findAllByText('Library Scan'))[0]).toBeInTheDocument();
|
|
|
|
fireEvent.click(screen.getAllByRole('button', { name: /Trigger Now/i })[0]);
|
|
fireEvent.click(screen.getByRole('button', { name: 'Trigger Job' }));
|
|
|
|
await waitFor(() => {
|
|
expect(fetchJSONMock).toHaveBeenCalledWith('/api/admin/jobs/job-1/trigger', {
|
|
method: 'POST',
|
|
});
|
|
expect(toastMock.success).toHaveBeenCalledWith('Job "Library Scan" triggered successfully');
|
|
});
|
|
|
|
expect(authenticatedFetcherMock.mock.calls.length).toBeGreaterThanOrEqual(2);
|
|
});
|
|
|
|
it('updates a job schedule using preset selection', async () => {
|
|
authenticatedFetcherMock.mockResolvedValue({
|
|
jobs: [
|
|
{
|
|
id: 'job-2',
|
|
name: 'Audible Refresh',
|
|
type: 'audible_refresh',
|
|
schedule: '0 * * * *',
|
|
enabled: true,
|
|
lastRun: null,
|
|
nextRun: null,
|
|
},
|
|
],
|
|
});
|
|
fetchJSONMock.mockResolvedValue({ success: true });
|
|
|
|
render(<AdminJobsPage />);
|
|
|
|
fireEvent.click((await screen.findAllByRole('button', { name: 'Edit' }))[0]);
|
|
fireEvent.click(screen.getByRole('radio', { name: /Every 2 hours/i }));
|
|
fireEvent.click(screen.getByRole('button', { name: 'Save Changes' }));
|
|
|
|
await waitFor(() => {
|
|
expect(fetchJSONMock).toHaveBeenCalledWith('/api/admin/jobs/job-2', {
|
|
method: 'PUT',
|
|
body: JSON.stringify({ schedule: '0 */2 * * *', enabled: true }),
|
|
});
|
|
expect(toastMock.success).toHaveBeenCalledWith('Job "Audible Refresh" updated successfully');
|
|
});
|
|
});
|
|
|
|
it('shows an error when jobs fail to load', async () => {
|
|
authenticatedFetcherMock.mockRejectedValue(new Error('boom'));
|
|
|
|
render(<AdminJobsPage />);
|
|
|
|
expect(await screen.findByText('Failed to load scheduled jobs')).toBeInTheDocument();
|
|
});
|
|
});
|