Move sections to where they read better: - Phase 1 (Team registration): drop the "Your Agent" block. - Phase 2 (Meet your agent): host the "Your Agent" section (say-hi / Telegram / voice) AND the agent chat under it; remove "Pick your domain". - Module 1 (Domain & events): "Pick your domain" moves here (no more read-only carry) alongside the ADD Layer 1 card. - Module 2 (Skills & policies): the chat is gone; the L2/L3 ADD cards show directly (still auto-prefilled if the three prompts ran in Meet your agent). Also: OpenYourNode opens the browser-reachable board URL. In self-host/USB mode the stored url is container-facing (host.docker.internal) which the browser can't resolve — derive the current host on :8080 instead. Tests updated. Co-Authored-By: Claude Opus 4.8 <[email protected]>
71 lines
2.3 KiB
TypeScript
71 lines
2.3 KiB
TypeScript
import { describe, it, expect, beforeEach, vi } from 'vitest'
|
|
import { render, screen, act, waitFor } from '@testing-library/react'
|
|
import userEvent from '@testing-library/user-event'
|
|
import { MemoryRouter } from 'react-router-dom'
|
|
import { Module1 } from './Module1'
|
|
import { useSession } from '@/store/session'
|
|
import type { WsEvent } from '@/types'
|
|
|
|
let emit: (e: WsEvent) => void = () => {}
|
|
vi.mock('@/lib/api', async (orig) => ({
|
|
...(await orig<typeof import('@/lib/api')>()),
|
|
openTeamActivity: (_teamId: string, on: (e: WsEvent) => void) => {
|
|
emit = on
|
|
return () => {}
|
|
},
|
|
getNodeStatus: vi.fn().mockResolvedValue({ teamId: 't', online: false }),
|
|
}))
|
|
|
|
function renderPage() {
|
|
return render(
|
|
<MemoryRouter>
|
|
<Module1 />
|
|
</MemoryRouter>,
|
|
)
|
|
}
|
|
|
|
describe('Module1', () => {
|
|
beforeEach(() => {
|
|
useSession.getState().reset()
|
|
sessionStorage.clear()
|
|
})
|
|
|
|
it('renders the heading', () => {
|
|
renderPage()
|
|
expect(screen.getByRole('heading', { name: /domain.*events/i })).toBeInTheDocument()
|
|
})
|
|
|
|
it('lets you pick the domain here (no read-only carry)', () => {
|
|
renderPage()
|
|
expect(screen.queryByTestId('domain-carried')).toBeNull()
|
|
expect(screen.getByPlaceholderText(/image measurement|structural stress|air quality/i)).toBeInTheDocument()
|
|
})
|
|
|
|
it('focuses on Layer 1 — no live board feed or actor map cards', () => {
|
|
renderPage()
|
|
expect(screen.queryByTestId('live-board-feed')).toBeNull()
|
|
expect(screen.queryByTestId('actor-map')).toBeNull()
|
|
})
|
|
|
|
it('gates Proceed until the board is online, a domain is named, and L1 is filled', async () => {
|
|
const user = userEvent.setup()
|
|
renderPage()
|
|
const proceed = screen.getByRole('button', { name: /proceed/i })
|
|
expect(proceed).toBeDisabled()
|
|
|
|
act(() => useSession.getState().setDomain('resonance'))
|
|
await user.type(screen.getByLabelText(/layer 1/i), 'structural resonance')
|
|
expect(proceed).toBeDisabled() // board not online yet
|
|
|
|
act(() => emit({ type: 'node:status', teamId: 'x', online: true }))
|
|
await waitFor(() => expect(proceed).toBeEnabled())
|
|
})
|
|
|
|
it('persists the Layer-1 domain text to the store as a string', async () => {
|
|
const user = userEvent.setup()
|
|
renderPage()
|
|
await user.type(screen.getByLabelText(/layer 1/i), 'detect resonance')
|
|
expect(useSession.getState().add.L1).toBe('detect resonance')
|
|
})
|
|
})
|