import { createElement } from 'react' import { act, create, type ReactTestRenderer } from 'react-test-renderer' import { afterEach, describe, expect, it, vi } from 'vitest' import { MobileSourceControlHeader } from './MobileSourceControlHeader' vi.mock('react-native', () => ({ Pressable: 'Pressable', Text: 'Text', View: 'View' })) vi.mock('lucide-react-native', () => ({ ChevronLeft: 'ChevronLeft', ExternalLink: 'ExternalLink', RefreshCw: 'RefreshCw', X: 'X' })) vi.mock('./mobile-source-control-styles', () => ({ styles: new Proxy({}, { get: () => ({}) }) })) // Dock dismissal and route Back need distinct controls; the dock never pops a route. describe('the source-control header control', () => { let tree: ReactTestRenderer | null = null afterEach(() => { act(() => tree?.unmount()) tree = null }) function render( embedded: boolean, handlers: { onBack: () => void; onClose: () => void }, ioBusy = false ) { let rendered: ReactTestRenderer | null = null act(() => { rendered = create( createElement(MobileSourceControlHeader, { embedded, worktreeLabel: 'wt', ioBusy, onRefresh: () => {}, ...handlers }) ) }) if (rendered === null) { throw new Error('the header did not render') } tree = rendered return rendered } const labelled = (rendered: ReactTestRenderer, label: string) => rendered.root.findAll((node) => node.props.accessibilityLabel === label) it('goes back from the route, named as a Back and pressing onBack', () => { const calls: string[] = [] const rendered = render(false, { onBack: () => calls.push('back'), onClose: () => calls.push('close') }) const control = labelled(rendered, 'Back to session').at(0) expect(control?.props.accessibilityRole).toBe('button') act(() => control?.props.onPress()) expect(calls).toEqual(['back']) expect(labelled(rendered, 'Close source control')).toHaveLength(0) }) it('closes the dock when embedded, named as a Close and pressing onClose', () => { const calls: string[] = [] const rendered = render(true, { onBack: () => calls.push('back'), onClose: () => calls.push('close') }) const control = labelled(rendered, 'Close source control').at(0) expect(control?.props.accessibilityRole).toBe('button') act(() => control?.props.onPress()) expect(calls).toEqual(['close']) expect(labelled(rendered, 'Back to session')).toHaveLength(0) }) it.each([false, true])('keeps navigation enabled during file I/O (embedded: %s)', (embedded) => { const onBack = vi.fn() const onClose = vi.fn() const rendered = render(embedded, { onBack, onClose }, true) const navigation = labelled(rendered, embedded ? 'Close source control' : 'Back to session').at( 0 ) expect(navigation?.props.disabled).not.toBe(true) expect(labelled(rendered, 'Refresh source control').at(0)?.props.disabled).toBe(true) act(() => navigation?.props.onPress()) expect(embedded ? onClose : onBack).toHaveBeenCalledTimes(1) expect(embedded ? onBack : onClose).not.toHaveBeenCalled() }) })