diff --git a/web/src/routes/admin/integrations/integrations.test.ts b/web/src/routes/admin/integrations/integrations.test.ts index 30b33732..a89eb2be 100644 --- a/web/src/routes/admin/integrations/integrations.test.ts +++ b/web/src/routes/admin/integrations/integrations.test.ts @@ -522,29 +522,38 @@ describe('/admin/integrations — SMTP card', () => { }); describe('Lidarr first-time setup (Test-then-Save)', () => { - afterEach(() => { - vi.clearAllMocks(); - }); + // Fresh-install variant of setup() — the three list queries return + // empty arrays so we can verify the dropdowns get populated from the + // test response, not from the (empty) cached query data. + function setupFresh() { + (createLidarrConfigQuery as ReturnType).mockReturnValue( + mockQuery({ data: cfgUnset }) + ); + (createQualityProfilesQuery as ReturnType).mockReturnValue(mockQuery({ data: [] })); + (createMetadataProfilesQuery as ReturnType).mockReturnValue(mockQuery({ data: [] })); + (createRootFoldersQuery as ReturnType).mockReturnValue(mockQuery({ data: [] })); + (createCoverProvidersQuery as ReturnType).mockReturnValue( + mockQuery({ data: defaultCoverProviders }) + ); + (createSMTPConfigQuery as ReturnType).mockReturnValue( + mockQuery({ data: smtpUnset }) + ); + return render(IntegrationsPage); + } test('Save calls test first, fills defaults from response, then put-config', async () => { - vi.mocked(createLidarrConfigQuery).mockReturnValue(mockQuery(cfgUnset)); - vi.mocked(createQualityProfilesQuery).mockReturnValue(mockQuery([])); - vi.mocked(createMetadataProfilesQuery).mockReturnValue(mockQuery([])); - vi.mocked(createRootFoldersQuery).mockReturnValue(mockQuery([])); - vi.mocked(createCoverProvidersQuery).mockReturnValue(mockQuery(defaultCoverProviders)); - vi.mocked(createSMTPConfigQuery).mockReturnValue(mockQuery(smtpUnset)); - vi.mocked(testLidarrConnection).mockResolvedValue(testResponseOk); - vi.mocked(putLidarrConfig).mockResolvedValue(cfgConnected); + setupFresh(); + (testLidarrConnection as ReturnType).mockResolvedValueOnce(testResponseOk); + (putLidarrConfig as ReturnType).mockResolvedValueOnce(cfgConnected); - render(IntegrationsPage); - - await fireEvent.input(screen.getByLabelText(/Base URL/i), { + const section = lidarrSection(); + await fireEvent.input(within(section).getByLabelText(/Base URL/i), { target: { value: 'http://lidarr.local' } }); - await fireEvent.input(screen.getByLabelText(/API key/i), { + await fireEvent.input(within(section).getByLabelText(/API key/i), { target: { value: 'secret-key' } }); - await fireEvent.click(screen.getByRole('button', { name: /Save changes/i })); + await fireEvent.click(within(section).getByRole('button', { name: /Save changes/i })); await waitFor(() => { expect(testLidarrConnection).toHaveBeenCalledWith({ @@ -565,64 +574,52 @@ describe('Lidarr first-time setup (Test-then-Save)', () => { }); test('Save aborts when test fails and surfaces the error', async () => { - vi.mocked(createLidarrConfigQuery).mockReturnValue(mockQuery(cfgUnset)); - vi.mocked(createQualityProfilesQuery).mockReturnValue(mockQuery([])); - vi.mocked(createMetadataProfilesQuery).mockReturnValue(mockQuery([])); - vi.mocked(createRootFoldersQuery).mockReturnValue(mockQuery([])); - vi.mocked(createCoverProvidersQuery).mockReturnValue(mockQuery(defaultCoverProviders)); - vi.mocked(createSMTPConfigQuery).mockReturnValue(mockQuery(smtpUnset)); - vi.mocked(testLidarrConnection).mockResolvedValue({ + setupFresh(); + (testLidarrConnection as ReturnType).mockResolvedValueOnce({ ok: false, error: 'lidarr_unreachable' }); - render(IntegrationsPage); - - await fireEvent.input(screen.getByLabelText(/Base URL/i), { + const section = lidarrSection(); + await fireEvent.input(within(section).getByLabelText(/Base URL/i), { target: { value: 'http://wrong.local' } }); - await fireEvent.input(screen.getByLabelText(/API key/i), { + await fireEvent.input(within(section).getByLabelText(/API key/i), { target: { value: 'k' } }); - await fireEvent.click(screen.getByRole('button', { name: /Save changes/i })); + await fireEvent.click(within(section).getByRole('button', { name: /Save changes/i })); await waitFor(() => { expect(testLidarrConnection).toHaveBeenCalled(); }); expect(putLidarrConfig).not.toHaveBeenCalled(); await waitFor(() => { - expect(screen.getByText(/Save failed — lidarr_unreachable/i)).toBeInTheDocument(); + expect(within(lidarrSection()).getByText(/save failed — lidarr_unreachable/i)).toBeInTheDocument(); }); }); test('Save preserves operator-picked defaults over auto-defaults', async () => { - vi.mocked(createLidarrConfigQuery).mockReturnValue(mockQuery(cfgUnset)); - vi.mocked(createQualityProfilesQuery).mockReturnValue(mockQuery([])); - vi.mocked(createMetadataProfilesQuery).mockReturnValue(mockQuery([])); - vi.mocked(createRootFoldersQuery).mockReturnValue(mockQuery([])); - vi.mocked(createCoverProvidersQuery).mockReturnValue(mockQuery(defaultCoverProviders)); - vi.mocked(createSMTPConfigQuery).mockReturnValue(mockQuery(smtpUnset)); - vi.mocked(testLidarrConnection).mockResolvedValue(testResponseOk); - vi.mocked(putLidarrConfig).mockResolvedValue(cfgConnected); + setupFresh(); + (testLidarrConnection as ReturnType).mockResolvedValue(testResponseOk); + (putLidarrConfig as ReturnType).mockResolvedValueOnce(cfgConnected); - render(IntegrationsPage); - - await fireEvent.input(screen.getByLabelText(/Base URL/i), { + const section = lidarrSection(); + await fireEvent.input(within(section).getByLabelText(/Base URL/i), { target: { value: 'http://lidarr.local' } }); - await fireEvent.input(screen.getByLabelText(/API key/i), { + await fireEvent.input(within(section).getByLabelText(/API key/i), { target: { value: 'secret-key' } }); // Click Test first to populate the dropdowns, then change the // quality profile selection before clicking Save. - await fireEvent.click(screen.getByRole('button', { name: /Test connection/i })); + await fireEvent.click(within(section).getByRole('button', { name: /Test connection/i })); await waitFor(() => { expect(testLidarrConnection).toHaveBeenCalledTimes(1); }); - const qualitySelect = screen.getByLabelText(/Default quality profile/i); + const qualitySelect = within(section).getByLabelText(/Default quality profile/i); await fireEvent.change(qualitySelect, { target: { value: '2' } }); - await fireEvent.click(screen.getByRole('button', { name: /Save changes/i })); + await fireEvent.click(within(section).getByRole('button', { name: /Save changes/i })); await waitFor(() => { expect(putLidarrConfig).toHaveBeenCalledWith(