import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { render, screen, waitFor } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { beforeEach, describe, expect, it, vi } from 'vitest' import { SourceAppPicker } from '../source-app-picker' const mocks = vi.hoisted(() => { const sourceAppsQuery = { data: { pages: [ { data: [ { id: 'app-1', name: 'Workflow App', }, ], }, ], }, error: null, fetchNextPage: vi.fn(), hasNextPage: true, isFetching: false, isFetchingNextPage: false, isLoading: false, } return { sourceAppsQuery, useInfiniteScroll: vi.fn(() => ({ rootRef: vi.fn(), sentinelRef: vi.fn(), })), } }) vi.mock('@/features/deployments/create-release/state', async () => { const { atom } = await import('jotai') return { createReleaseSourceAppsAtom: atom(() => mocks.sourceAppsQuery.data.pages.flatMap((page) => page.data), ), createReleaseSourceAppsErrorAtom: atom(() => mocks.sourceAppsQuery.error), createReleaseSourceAppsFetchNextPageAtom: atom(() => mocks.sourceAppsQuery.fetchNextPage), createReleaseSourceAppsHasNextPageAtom: atom(() => mocks.sourceAppsQuery.hasNextPage), createReleaseSourceAppsIsFetchingAtom: atom(() => mocks.sourceAppsQuery.isFetching), createReleaseSourceAppsIsFetchingNextPageAtom: atom( () => mocks.sourceAppsQuery.isFetchingNextPage, ), createReleaseSourceAppsIsLoadingAtom: atom(() => mocks.sourceAppsQuery.isLoading), createReleaseSourceAppSearchTextAtom: atom(''), createReleaseSourceAppsQueryAtom: atom(mocks.sourceAppsQuery), } }) vi.mock('@/features/deployments/shared/hooks/use-infinite-scroll', () => ({ useInfiniteScroll: mocks.useInfiniteScroll, })) function renderSourceAppPicker(disabled: boolean) { const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false, }, }, }) return render( undefined} disabled={disabled} /> , ) } describe('SourceAppPicker', () => { beforeEach(() => { vi.clearAllMocks() Object.assign(mocks.sourceAppsQuery, { data: { pages: [ { data: [ { id: 'app-1', name: 'Workflow App', }, ], }, ], }, error: null, fetchNextPage: vi.fn(), hasNextPage: true, isFetching: false, isFetchingNextPage: false, isLoading: false, }) }) it('should disable the switch control when disabled', () => { renderSourceAppPicker(true) expect(screen.getByText('Workflow 1')).toBeInTheDocument() expect( screen.getByRole('combobox', { name: 'deployments.versions.sourceAppOption' }), ).toBeDisabled() }) it('should use infinite scroll to load more apps when the picker is open', async () => { const user = userEvent.setup() renderSourceAppPicker(false) expect(mocks.useInfiniteScroll).toHaveBeenCalledWith( expect.objectContaining({ fetchNextPage: expect.any(Function), hasNextPage: true, isFetching: false, isFetchingNextPage: false, isLoading: false, }), expect.objectContaining({ enabled: false, rootMargin: '0px 0px 160px 0px', threshold: 0.1, }), ) await user.click(screen.getByRole('combobox', { name: 'deployments.versions.sourceAppOption' })) await waitFor(() => { expect(mocks.useInfiniteScroll).toHaveBeenLastCalledWith( expect.objectContaining({ fetchNextPage: expect.any(Function), hasNextPage: true, isFetching: false, isFetchingNextPage: false, isLoading: false, }), expect.objectContaining({ enabled: true, rootMargin: '0px 0px 160px 0px', threshold: 0.1, }), ) }) expect( screen.queryByRole('button', { name: /createModal\.loadMoreApps/ }), ).not.toBeInTheDocument() }) })