test(desktop): cover projects RPC capability probing

Regression tests for stale-backend detection when projects.create is
missing from an older backend that still reports the same semver.
This commit is contained in:
xxxigm 2026-06-30 21:23:38 +07:00
parent f3d2dfbec6
commit 217b3c283a
2 changed files with 70 additions and 0 deletions

View file

@ -0,0 +1,16 @@
import { describe, expect, it } from 'vitest'
import { isMissingRpcMethod } from './gateway-rpc'
describe('isMissingRpcMethod', () => {
it('detects JSON-RPC method-not-found errors', () => {
expect(isMissingRpcMethod(new Error('unknown method: projects.create'))).toBe(true)
expect(isMissingRpcMethod(new Error('Method not found'))).toBe(true)
expect(isMissingRpcMethod(new Error('RPC failed: -32601'))).toBe(true)
})
it('ignores unrelated failures', () => {
expect(isMissingRpcMethod(new Error('Hermes gateway is not connected'))).toBe(false)
expect(isMissingRpcMethod(new Error('no such project'))).toBe(false)
})
})

View file

@ -5,15 +5,26 @@ import { $sidebarAgentsGrouped } from '@/store/layout'
import {
$activeProjectId,
$projectScope,
$projectsRpcAvailable,
$worktreeRefreshToken,
ALL_PROJECTS,
createProject,
enterProject,
exitProjectScope,
openProjectCreate,
pickProjectFolder,
refreshProjects,
refreshWorktrees
} from './projects'
vi.mock('@/i18n', () => ({
translateNow: (key: string) => key
}))
vi.mock('@/store/notifications', () => ({
notify: vi.fn()
}))
vi.mock('@/lib/desktop-fs', () => ({
desktopDefaultCwd: vi.fn(),
isDesktopFsRemoteMode: vi.fn(),
@ -33,6 +44,8 @@ const selectDesktopPaths = vi.mocked(fs.selectDesktopPaths)
const gw = await import('@/store/gateway')
const activeGateway = vi.mocked(gw.activeGateway)
const notifications = await import('@/store/notifications')
const notify = vi.mocked(notifications.notify)
describe('project scope', () => {
beforeEach(() => {
@ -115,6 +128,7 @@ describe('createProject', () => {
vi.clearAllMocks()
$sidebarAgentsGrouped.set(false)
$activeProjectId.set(null)
$projectsRpcAvailable.set(null)
})
it('creates the project and flips into the grouped view so a blank slate shows it', async () => {
@ -139,4 +153,44 @@ describe('createProject', () => {
expect($sidebarAgentsGrouped.get()).toBe(true)
expect($activeProjectId.get()).toBe('p_new')
})
it('marks the backend stale and surfaces a friendly error when projects.create is missing', async () => {
activeGateway.mockReturnValue({
connectionState: 'open',
request: vi.fn().mockRejectedValue(new Error('unknown method: projects.create'))
} as never)
await expect(createProject({ folders: ['/srv/demo'], name: 'Demo' })).rejects.toThrow(
'sidebar.projects.staleBackend'
)
expect($projectsRpcAvailable.get()).toBe(false)
})
})
describe('projects RPC capability', () => {
beforeEach(() => {
vi.clearAllMocks()
$projectsRpcAvailable.set(null)
})
it('marks the backend stale when projects.list is missing', async () => {
activeGateway.mockReturnValue({
connectionState: 'open',
request: vi.fn().mockRejectedValue(new Error('unknown method: projects.list'))
} as never)
await refreshProjects()
expect($projectsRpcAvailable.get()).toBe(false)
})
it('blocks opening the create dialog once the backend is known stale', () => {
$projectsRpcAvailable.set(false)
openProjectCreate()
expect(notify).toHaveBeenCalledWith(
expect.objectContaining({ kind: 'warning', message: 'sidebar.projects.staleBackend' })
)
})
})