Rework the Meet-your-agent rail into a self-contained agent surface: - Clawd, the Claude Code pixel crab, animates the LED matrix on a 26x16 grid, coupled to the chat lifecycle (idle stare / claws pump while working / green flash on reply). Static antennas, permanent black eyes. - A full free-form chat to the default agent (useAgentChat): free text goes to the blocking /webhook path so conversational replies actually render; the 3 canned prompts stay fire-and-forget + SSE (tool turns). - Chat and the working log are separate panes; the 3 prompts became starter buttons; the ZeroClaw runtime + channels moved into an Advanced drawer. The whole agent rail is now theme-aware (light/dark). - Strip the phase eyebrows from the sidebar + page headers; reduce the EnvSetup left column to editorial copy. Co-Authored-By: Claude Opus 4.8 <[email protected]>
53 lines
1.8 KiB
TypeScript
53 lines
1.8 KiB
TypeScript
import { describe, it, expect, beforeEach, vi } from 'vitest'
|
|
import { render, screen } from '@testing-library/react'
|
|
import { MemoryRouter } from 'react-router-dom'
|
|
import { EnvSetup } from './EnvSetup'
|
|
import { useSession } from '@/store/session'
|
|
|
|
// The chat, starters, runtime and channels all moved to the cockpit rail
|
|
// (CockpitRail's "agent" variant) — the page itself is now editorial copy + a
|
|
// proceed gate. Stub the mode call the rail would otherwise make elsewhere.
|
|
vi.mock('@/lib/api', async (orig) => ({
|
|
...(await orig<typeof import('@/lib/api')>()),
|
|
getMode: () => Promise.resolve({ localMode: false }),
|
|
}))
|
|
|
|
function renderPage() {
|
|
return render(
|
|
<MemoryRouter>
|
|
<EnvSetup />
|
|
</MemoryRouter>,
|
|
)
|
|
}
|
|
|
|
function connect(nodeUrl: string | null = 'http://192.168.1.7:8080') {
|
|
useSession.getState().setDevice({ connected: true, port: 'board · crimson-otter', uptimeS: 0, nodeUrl })
|
|
}
|
|
|
|
describe('EnvSetup — Meet your agent', () => {
|
|
beforeEach(() => {
|
|
useSession.getState().reset()
|
|
sessionStorage.clear()
|
|
})
|
|
|
|
it('renders the heading and the editorial intro', () => {
|
|
renderPage()
|
|
expect(screen.getByRole('heading', { name: /meet your agent/i })).toBeInTheDocument()
|
|
expect(screen.getByTestId('agent-intro')).toBeInTheDocument()
|
|
})
|
|
|
|
it('guides to connect the board first when not connected, and gates Proceed', () => {
|
|
renderPage()
|
|
expect(screen.getByText(/connect your board on the previous step/i)).toBeInTheDocument()
|
|
expect(screen.getByRole('button', { name: /proceed/i })).toBeDisabled()
|
|
})
|
|
|
|
it('enables Proceed once the board is connected', () => {
|
|
connect()
|
|
renderPage()
|
|
expect(screen.getByRole('button', { name: /proceed/i })).toBeEnabled()
|
|
// the connect nudge disappears once online
|
|
expect(screen.queryByText(/connect your board on the previous step/i)).toBeNull()
|
|
})
|
|
})
|