test(desktop): cover permission guard transitions

Exercise controlled changes, repeated trigger closure, tab switches, and both bypass dialog close paths so the changed-line coverage gate proves the full active-turn guard.\n\nTested: desktop PermissionModeSelector 14/14; adapters and H5 auth 51/51\nConfidence: high\nScope-risk: narrow
This commit is contained in:
程序员阿江(Relakkes) 2026-07-10 23:05:57 +08:00
parent 173d6a84fc
commit 46dca4e961
2 changed files with 67 additions and 4 deletions

View File

@ -406,4 +406,69 @@ describe('PermissionModeSelector', () => {
expect(setSessionPermissionMode).not.toHaveBeenCalled()
expect(screen.queryByRole('dialog', { name: 'Enable bypass mode' })).not.toBeInTheDocument()
})
it('reports controlled permission changes through onChange', () => {
const onChange = vi.fn()
render(<PermissionModeSelector value="default" onChange={onChange} />)
fireEvent.click(screen.getByRole('button', { name: 'Ask permissions' }))
fireEvent.click(screen.getByRole('menuitem', { name: /Auto accept edits/ }))
expect(onChange).toHaveBeenCalledWith('acceptEdits')
})
it('closes the permission menu when its trigger is clicked again', () => {
render(<PermissionModeSelector />)
const trigger = screen.getByRole('button', { name: 'Ask permissions' })
fireEvent.click(trigger)
expect(trigger).toHaveAttribute('aria-expanded', 'true')
fireEvent.click(trigger)
expect(trigger).toHaveAttribute('aria-expanded', 'false')
})
it('closes the permission menu when the active tab changes', () => {
useChatStore.setState({
sessions: {
'current-tab': makeChatSession('idle'),
'next-tab': makeChatSession('idle'),
},
})
useTabStore.setState({
activeTabId: 'current-tab',
tabs: [{ sessionId: 'current-tab', title: 'Current', type: 'session', status: 'idle' }],
})
render(<PermissionModeSelector />)
fireEvent.click(screen.getByRole('button', { name: 'Ask permissions' }))
act(() => {
useTabStore.setState({
activeTabId: 'next-tab',
tabs: [{ sessionId: 'next-tab', title: 'Next', type: 'session', status: 'idle' }],
})
})
expect(screen.queryByRole('menu')).not.toBeInTheDocument()
})
it('closes bypass confirmation through both dialog close actions', () => {
render(<PermissionModeSelector />)
const openDialog = () => {
fireEvent.click(screen.getByRole('button', { name: 'Ask permissions' }))
fireEvent.click(screen.getByRole('menuitem', { name: /Bypass permissions/ }))
}
openDialog()
fireEvent.click(screen.getByRole('button', { name: 'Close dialog' }))
expect(screen.queryByRole('dialog', { name: 'Enable bypass mode' })).not.toBeInTheDocument()
openDialog()
fireEvent.click(screen.getByRole('button', { name: 'Cancel' }))
expect(screen.queryByRole('dialog', { name: 'Enable bypass mode' })).not.toBeInTheDocument()
})
})

View File

@ -84,12 +84,10 @@ export async function handleApiRequest(req: Request, url: URL): Promise<Response
case 'haha-openai-oauth':
return handleHahaOpenAIOAuthApi(req, url, segments)
case 'adapters': {
case 'adapters':
// Adapter protocols pull in platform SDKs that are unnecessary for the
// core server path. Load them only when this API is actually used.
const { handleAdaptersApi } = await import('./api/adapters.js')
return handleAdaptersApi(req, url, segments)
}
return (await import('./api/adapters.js')).handleAdaptersApi(req, url, segments)
case 'skills':
return handleSkillsApi(req, url, segments)