import { AuthSession } from '@pipu/core'; import { createI18n } from '@pipu/i18n'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { cleanup, render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { I18nextProvider } from 'react-i18next'; import { afterEach, expect, it } from 'vitest'; import { SessionProvider } from '../../app/session'; import { GeniusPanel } from './GeniusPanel'; afterEach(cleanup); const initial = { configured: true, paused: false, running: true, total: 100, pending: 80, matched: 17, lyrics: 15, annotations: 5, images: 17, unmatched: 2, errors: 1, last_error: '', cooldown_until: '2000-01-01T00:00:00Z', }; async function fixture(overrides: Partial = {}) { let data = { ...initial, ...overrides }; const actions: string[] = []; const session = new AuthSession({ baseUrl: 'http://localhost', clientType: 'web', fetch: async (url, init) => { const request = new Request(url, init); if (request.method === 'POST') { const { action } = await request.json() as { action: string }; actions.push(action); data = { ...data, paused: action === 'pause' }; } return new Response(JSON.stringify(data), { headers: { 'Content-Type': 'application/json' } }); } }); const client = new QueryClient({ defaultOptions: { queries: { retry: false, staleTime: Infinity } } }); client.setQueryData(['genius-stats'], data); const i18n = await createI18n('ru'); render( ); return { actions, user: userEvent.setup() }; } it.each<[Partial, string]>([ [{}, 'Получение данных из Genius…'], [{ running: false }, 'Очередь ожидает обработки'], [{ paused: true }, 'Обработка приостановлена'], [{ cooldown_until: '2099-01-01T00:00:00Z' }, 'Ожидание после ограничения Genius'], [{ running: false, pending: 0 }, 'Ожидание новых треков'], ])('shows queue state and progress for %j', async (overrides, status) => { await fixture(overrides); expect(screen.getByRole('status')).toHaveTextContent(status); const progress = screen.getByRole('progressbar', { name: 'Прогресс обработки Genius' }); expect(progress).toHaveAttribute('max', '100'); expect(progress).toHaveAttribute('value', String(100 - (overrides.pending ?? 80))); }); it('pauses and resumes the existing queue without requesting a retry', async () => { const { user, actions } = await fixture(); await user.click(screen.getByRole('button', { name: 'Приостановить обработку' })); await user.click(await screen.findByRole('button', { name: 'Продолжить обработку' })); expect(actions).toEqual(['pause', 'start']); expect(screen.getByRole('progressbar')).toHaveAttribute('value', '20'); }); it('explains the retry scope and sends the retry action', async () => { const { user, actions } = await fixture(); expect(screen.getByText(/Повтор добавит в очередь только/)).toBeVisible(); await user.click(screen.getByRole('button', { name: 'Добавить проблемные треки в очередь' })); expect(actions).toEqual(['retry']); });