mirror of
https://github.com/stablyai/orca.git
synced 2026-10-08 16:02:37 +00:00
200 lines
6.1 KiB
TypeScript
200 lines
6.1 KiB
TypeScript
import { createElement } from 'react'
|
|
import { act, create, type ReactTestRenderer } from 'react-test-renderer'
|
|
import { afterEach, describe, expect, it, vi } from 'vitest'
|
|
import { MobileHostCard } from './MobileHostCard'
|
|
|
|
vi.mock('react-native', () => ({
|
|
Pressable: 'Pressable',
|
|
StyleSheet: { create: (styles: unknown) => styles },
|
|
Text: 'Text',
|
|
View: 'View'
|
|
}))
|
|
|
|
vi.mock('lucide-react-native', () => ({
|
|
Monitor: 'Monitor',
|
|
MoreVertical: 'MoreVertical'
|
|
}))
|
|
|
|
vi.mock('./StatusDot', () => ({
|
|
StatusDot: 'StatusDot'
|
|
}))
|
|
|
|
function suppressRendererDeprecation() {
|
|
return vi.spyOn(console, 'error').mockImplementation((...args) => {
|
|
if (typeof args[0] !== 'string' || !args[0].includes('react-test-renderer is deprecated')) {
|
|
throw new Error(String(args[0]))
|
|
}
|
|
})
|
|
}
|
|
|
|
describe('MobileHostCard', () => {
|
|
let renderer: ReactTestRenderer | null = null
|
|
|
|
afterEach(() => {
|
|
act(() => renderer?.unmount())
|
|
renderer = null
|
|
vi.restoreAllMocks()
|
|
})
|
|
|
|
it('keeps host navigation and actions as separate accessible controls', async () => {
|
|
const onPress = vi.fn()
|
|
const onLongPress = vi.fn()
|
|
const onOpenActions = vi.fn()
|
|
const consoleError = suppressRendererDeprecation()
|
|
await act(async () => {
|
|
renderer = create(
|
|
createElement(MobileHostCard, {
|
|
host: {
|
|
id: 'desk',
|
|
name: 'Desk',
|
|
endpoint: 'ws://192.168.1.2:6768',
|
|
deviceToken: 'token',
|
|
publicKeyB64: 'key',
|
|
lastConnected: 1
|
|
},
|
|
state: 'disconnected',
|
|
verdict: { kind: 'normal', label: 'Disconnected' },
|
|
path: 'lan',
|
|
onPress,
|
|
onLongPress,
|
|
onOpenActions
|
|
})
|
|
)
|
|
})
|
|
consoleError.mockRestore()
|
|
|
|
const buttons = renderer.root.findAllByType('Pressable')
|
|
expect(buttons).toHaveLength(2)
|
|
expect(buttons[0].props.accessibilityRole).toBe('button')
|
|
expect(buttons[0].props.accessibilityLabel).toBe('Open Desk, Disconnected')
|
|
expect(buttons[1].props.accessibilityRole).toBe('button')
|
|
expect(buttons[1].props.accessibilityLabel).toBe('Actions for Desk')
|
|
expect(buttons[1].props.hitSlop).toBe(8)
|
|
expect(buttons[1].props.style({ pressed: false })[0]).toMatchObject({ width: 40, height: 40 })
|
|
expect(renderer.root.findAllByType('MoreVertical')).toHaveLength(1)
|
|
expect(renderer.root.findAllByType('ChevronRight')).toHaveLength(0)
|
|
|
|
act(() => buttons[1].props.onPress())
|
|
expect(onOpenActions).toHaveBeenCalledOnce()
|
|
expect(onPress).not.toHaveBeenCalled()
|
|
|
|
act(() => buttons[0].props.onPress())
|
|
act(() => buttons[0].props.onLongPress())
|
|
expect(onPress).toHaveBeenCalledOnce()
|
|
expect(onLongPress).toHaveBeenCalledOnce()
|
|
})
|
|
|
|
it('announces the connection path without the visual separator', async () => {
|
|
const consoleError = suppressRendererDeprecation()
|
|
await act(async () => {
|
|
renderer = create(
|
|
createElement(MobileHostCard, {
|
|
host: {
|
|
id: 'desk',
|
|
name: 'Desk',
|
|
endpoint: 'ws://192.168.1.2:6768',
|
|
deviceToken: 'token',
|
|
publicKeyB64: 'key',
|
|
lastConnected: 1
|
|
},
|
|
state: 'connected',
|
|
verdict: { kind: 'normal', label: 'Connected' },
|
|
path: 'tailscale',
|
|
worktreeInfo: {
|
|
hostId: 'desk',
|
|
totalWorktrees: 3,
|
|
activeCount: 2,
|
|
lastActiveWorktree: null,
|
|
countsProvenAt: Date.now()
|
|
},
|
|
onPress: vi.fn(),
|
|
onLongPress: vi.fn(),
|
|
onOpenActions: vi.fn()
|
|
})
|
|
)
|
|
})
|
|
consoleError.mockRestore()
|
|
|
|
const navigationButton = renderer.root.findAllByType('Pressable')[0]
|
|
expect(navigationButton.props.accessibilityLabel).toBe(
|
|
'Open Desk, Connected, Direct via Tailscale, 3 worktrees, 2 active'
|
|
)
|
|
})
|
|
|
|
it('preserves the connected worktree-catalog failure state', async () => {
|
|
const consoleError = suppressRendererDeprecation()
|
|
await act(async () => {
|
|
renderer = create(
|
|
createElement(MobileHostCard, {
|
|
host: {
|
|
id: 'desk',
|
|
name: 'Desk',
|
|
endpoint: 'ws://192.168.1.2:6768',
|
|
deviceToken: 'token',
|
|
publicKeyB64: 'key',
|
|
lastConnected: 1
|
|
},
|
|
state: 'connected',
|
|
verdict: { kind: 'normal', label: 'Connected' },
|
|
path: 'relay',
|
|
worktreeInfo: {
|
|
hostId: 'desk',
|
|
totalWorktrees: 0,
|
|
activeCount: 0,
|
|
lastActiveWorktree: null,
|
|
catalogUnavailable: true
|
|
},
|
|
onPress: vi.fn(),
|
|
onLongPress: vi.fn(),
|
|
onOpenActions: vi.fn()
|
|
})
|
|
)
|
|
})
|
|
consoleError.mockRestore()
|
|
|
|
const navigationButton = renderer.root.findAllByType('Pressable')[0]
|
|
expect(navigationButton.props.accessibilityLabel).toBe(
|
|
'Open Desk, Connected, Orca Relay, Worktree list unavailable'
|
|
)
|
|
expect(
|
|
renderer.root
|
|
.findAllByType('Text')
|
|
.some((node) => node.children.includes('Worktree list unavailable'))
|
|
).toBe(true)
|
|
})
|
|
|
|
it('includes visible offline recovery guidance in the navigation label', async () => {
|
|
const consoleError = suppressRendererDeprecation()
|
|
await act(async () => {
|
|
renderer = create(
|
|
createElement(MobileHostCard, {
|
|
host: {
|
|
id: 'desk',
|
|
name: 'Desk',
|
|
endpoint: 'ws://192.168.1.2:6768',
|
|
deviceToken: 'token',
|
|
publicKeyB64: 'key',
|
|
lastConnected: 1
|
|
},
|
|
state: 'reconnecting',
|
|
verdict: {
|
|
kind: 'unreachable',
|
|
label: "Can't reach desktop",
|
|
reason: 'never-connected'
|
|
},
|
|
path: 'lan',
|
|
onPress: vi.fn(),
|
|
onLongPress: vi.fn(),
|
|
onOpenActions: vi.fn()
|
|
})
|
|
)
|
|
})
|
|
consoleError.mockRestore()
|
|
|
|
const navigationButton = renderer.root.findAllByType('Pressable')[0]
|
|
expect(navigationButton.props.accessibilityLabel).toBe(
|
|
"Open Desk, Can't reach desktop, Update desktop Orca and sign in to connect from anywhere"
|
|
)
|
|
})
|
|
})
|