Files
opsxshell/test/components/LauncherSerial.acceptance.test.tsx
T

108 lines
3.9 KiB
TypeScript

import { render, screen, waitFor, within } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import App from '../../src/app/App'
import QuickLauncher from '../../src/components/sessions/QuickLauncher'
import SerialConnectDialog from '../../src/components/serial/SerialConnectDialog'
import { useSessionStore } from '../../src/stores/sessionStore'
import { useTabStore } from '../../src/stores/tabStore'
import { mockDesktopApi } from '../setup'
const serialMocks = vi.hoisted(() => ({
listSerialPorts: vi.fn(),
}))
vi.mock('../../src/platform/serial', () => ({
listSerialPorts: serialMocks.listSerialPorts,
}))
describe('Quick launcher and serial acceptance', () => {
beforeEach(() => {
vi.clearAllMocks()
window.opsxApi = mockDesktopApi
serialMocks.listSerialPorts.mockResolvedValue([
{ path: '/dev/tty.debug-console', portType: 'Serial' },
{ path: '/dev/tty.Bluetooth-Incoming-Port', portType: 'Bluetooth' },
])
useSessionStore.setState({ sessions: [] })
useTabStore.setState({
tabs: [{ id: 'welcome', title: '欢迎', type: 'welcome', isActive: true }],
activeTabId: 'welcome',
})
})
it('opens the unified launcher from the tab-bar plus button', async () => {
const user = userEvent.setup()
render(<App />)
await user.click(screen.getByRole('button', { name: '快速启动' }))
expect(await screen.findByRole('heading', { name: '快速启动' })).toBeVisible()
const launcher = within(screen.getByRole('dialog'))
expect(launcher.getByRole('button', { name: /串口终端/ })).toBeVisible()
expect(launcher.getByRole('button', { name: /快速连接/ })).toBeVisible()
})
it('starts the system-default zsh directly from the launcher', async () => {
const user = userEvent.setup()
render(
<QuickLauncher
isOpen
onClose={vi.fn()}
onNewSession={vi.fn()}
onQuickConnect={vi.fn()}
onSerialConnect={vi.fn()}
/>
)
const zshButton = await screen.findByRole('button', {
name: /Zsh.*\/bin\/zsh.*系统默认/,
})
await user.click(zshButton)
expect(useTabStore.getState().tabs).toContainEqual(
expect.objectContaining({
title: 'Zsh',
type: 'terminal',
isLocal: true,
localShellPath: '/bin/zsh',
localShellKind: 'zsh',
})
)
})
it('maps the selected serial device and line settings into a serial config', async () => {
const user = userEvent.setup()
const onConnect = vi.fn()
render(<SerialConnectDialog isOpen onClose={vi.fn()} onConnect={onConnect} />)
await user.click(
await screen.findByRole('button', { name: /\/dev\/tty\.Bluetooth-Incoming-Port/ })
)
await user.selectOptions(screen.getByLabelText('波特率'), '921600')
await user.selectOptions(screen.getByLabelText('数据位'), '7')
await user.selectOptions(screen.getByLabelText('停止位'), '2')
await user.selectOptions(screen.getByLabelText('校验'), 'even')
await user.selectOptions(screen.getByLabelText('流控'), 'hardware')
await user.click(screen.getByRole('button', { name: '打开串口' }))
expect(onConnect).toHaveBeenCalledWith({
path: '/dev/tty.Bluetooth-Incoming-Port',
baudRate: 921600,
dataBits: 7,
stopBits: 2,
parity: 'even',
flowControl: 'hardware',
})
})
it('keeps the documented manual serial path when enumeration returns no devices', async () => {
serialMocks.listSerialPorts.mockResolvedValue([])
render(<SerialConnectDialog isOpen onClose={vi.fn()} onConnect={vi.fn()} />)
await waitFor(() => expect(serialMocks.listSerialPorts).toHaveBeenCalled())
expect(screen.getByLabelText('设备')).toHaveValue('/dev/tty.debug-console')
expect(screen.getByText(/\/dev\/tty\.Bluetooth-Incoming-Port/)).toBeVisible()
})
})