import { QueryClientProvider } from '@tanstack/react-query' import { render } from '@testing-library/react-native' import React, { Suspense } from 'react' import { buildTestQueryClient } from '../../../__utils__/query_client' import { AudioAdapter, ChatAdapters, ClipboardAdapter, ImagePickerAdapter, MenuAdapter, VideoAdapter, } from '../../../utils/native_adapters' import { ConversationsScreen } from '../conversations_screen' const mockGet = jest.fn() jest.mock('../../../hooks/use_api_client', () => ({ useApiClient: () => ({ chat: { get: mockGet } }), })) jest.mock('../../../hooks/use_product_analytics', () => ({ ...jest.requireActual('../../../hooks/use_product_analytics'), usePublishProductAnalyticsEvent: () => {}, })) jest.mock('../../../contexts/conversations_context', () => ({ ConversationsContextProvider: ({ children }: { children: React.ReactNode }) => children, })) jest.mock('../../../components', () => ({ Conversations: ({ ListHeaderComponent }: { ListHeaderComponent: React.ComponentType }) => ( ), })) jest.mock('../components/list_header_component', () => { const { Text } = require('react-native') return { ListHeaderComponent: () => Default header } }) jest.mock('../components/search_list_header_component', () => { const { Text } = require('react-native') return { SearchListHeaderComponent: () => Search header } }) jest.mock('../components/filter_dropdown_list_header_component', () => { const { Text } = require('react-native') return { FilterDropdownListHeaderComponent: () => Filter dropdown header } }) const configureAdapters = ({ menu }: { menu: boolean }) => { ChatAdapters.configure({ clipboard: new ClipboardAdapter({ getStringAsync: async () => '', setStringAsync: async () => {}, }), audio: new AudioAdapter({ useAudio: () => ({}) as any }), video: new VideoAdapter({ Player: (() => null) as any }), imagePicker: new ImagePickerAdapter({ openCameraAsync: async () => ({ canceled: true, assets: null }), openImageLibraryAsync: async () => ({ canceled: true, assets: null }), }), ...(menu ? { menu: new MenuAdapter({ View: () => null }) } : {}), }) } const renderWithFeatures = (enabledFeatures: string[]) => { mockGet.mockResolvedValue({ data: enabledFeatures.map((name, index) => ({ type: 'Feature', id: String(index + 1), name, enabled: true, })), links: {}, meta: { count: enabledFeatures.length, totalCount: enabledFeatures.length }, }) return render( ) } describe('ConversationsScreen header gating', () => { beforeEach(() => { configureAdapters({ menu: true }) }) it('shows the search header with only the QA flag on', async () => { const view = renderWithFeatures(['QA_MOBILE_search']) expect(await view.findByText('Search header')).toBeTruthy() }) it('shows the search header with only the rollout flag on', async () => { const view = renderWithFeatures(['ROLLOUT_MOBILE_search']) expect(await view.findByText('Search header')).toBeTruthy() }) it('shows the filter dropdown header over the search header when its flag is on', async () => { const view = renderWithFeatures(['QA_MOBILE_filter_dropdown', 'ROLLOUT_MOBILE_search']) expect(await view.findByText('Filter dropdown header')).toBeTruthy() }) it('shows the filter dropdown header with only its rollout flag on', async () => { const view = renderWithFeatures(['ROLLOUT_MOBILE_filter_dropdown']) expect(await view.findByText('Filter dropdown header')).toBeTruthy() }) it('falls back to the search header when the host has no menu adapter', async () => { configureAdapters({ menu: false }) const view = renderWithFeatures(['QA_MOBILE_filter_dropdown', 'ROLLOUT_MOBILE_search']) expect(await view.findByText('Search header')).toBeTruthy() }) it('shows the default header with neither flag on', async () => { const view = renderWithFeatures(['ROLLOUT_WEB_search']) expect(await view.findByText('Default header')).toBeTruthy() }) })