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()
})
})