hermes-agent / apps /desktop /src /lib /desktop-git.test.ts
SaylorTwift's picture
SaylorTwift HF Staff
Add files using upload-large-folder tool
a1b6014 verified
Raw History Blame Contribute Delete
5.3 kB
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { setApiRequestConnection } from '@/hermes'
import { $connection } from '@/store/session'
import { desktopGit } from './desktop-git'
const repoStatus = vi.fn(async () => ({ branch: 'main' }))
const worktreeList = vi.fn(async () => [{ branch: 'main', detached: false, isMain: true, locked: false, path: '/r' }])
const localGit = { repoStatus, review: { stage: vi.fn() }, worktreeList }
const api = vi.fn(async ({ path }: { path: string }) => {
if (path.startsWith('/api/git/status')) {
return { branch: 'remote-main' }
}
if (path.startsWith('/api/git/worktrees')) {
return { worktrees: [{ branch: 'main', detached: false, isMain: true, locked: false, path: '/srv/r' }] }
}
if (path.startsWith('/api/git/review/diff')) {
return { diff: 'remote-diff' }
}
if (path.startsWith('/api/git/branches')) {
return {
branches: [{ checkedOut: false, isDefault: false, isRemote: true, name: 'origin/feature', worktreePath: null }]
}
}
return { ok: true }
})
describe('desktop git facade', () => {
beforeEach(() => {
vi.stubGlobal('window', { hermesDesktop: { api, git: localGit } })
$connection.set(null)
})
afterEach(() => {
setApiRequestConnection(null)
vi.unstubAllGlobals()
vi.clearAllMocks()
$connection.set(null)
})
it('returns undefined after the renderer global is torn down', () => {
vi.stubGlobal('window', undefined)
expect(desktopGit()).toBeUndefined()
})
it('uses Electron git locally', async () => {
$connection.set({ mode: 'local' } as never)
await expect(desktopGit()?.repoStatus('/work')).resolves.toEqual({ branch: 'main' })
expect(repoStatus).toHaveBeenCalledWith('/work')
expect(api).not.toHaveBeenCalled()
})
it('routes reads through the backend REST mirror on a remote gateway', async () => {
$connection.set({ mode: 'remote' } as never)
await expect(desktopGit()?.repoStatus('/srv/work')).resolves.toEqual({ branch: 'remote-main' })
expect(api).toHaveBeenCalledWith({ path: '/api/git/status?path=%2Fsrv%2Fwork' })
// List endpoints unwrap their envelope to the bare array the bridge returns.
await expect(desktopGit()?.worktreeList('/srv/work')).resolves.toEqual([
{ branch: 'main', detached: false, isMain: true, locked: false, path: '/srv/r' }
])
// review.diff unwraps { diff } to a string.
await expect(desktopGit()?.review.diff('/srv/work', 'a.txt', 'uncommitted', null, false)).resolves.toBe(
'remote-diff'
)
expect(repoStatus).not.toHaveBeenCalled()
})
it('targets the active profile backend so a remote profile never touches the local repo', async () => {
$connection.set({ mode: 'remote', profile: 'remote-docker' } as never)
await desktopGit()?.repoStatus('/srv/work')
await desktopGit()?.review.stage('/srv/work', 'a.txt')
expect(api).toHaveBeenCalledWith({ path: '/api/git/status?path=%2Fsrv%2Fwork', profile: 'remote-docker' })
expect(api).toHaveBeenCalledWith({
body: { file: 'a.txt', path: '/srv/work' },
method: 'POST',
path: '/api/git/review/stage',
profile: 'remote-docker'
})
})
it('routes remote git reads and writes through the active registered gateway', async () => {
setApiRequestConnection('remote-user')
$connection.set({ mode: 'remote', profile: 'default' } as never)
await desktopGit()?.repoStatus('/srv/work')
await desktopGit()?.review.stage('/srv/work', 'a.txt')
expect(api).toHaveBeenCalledWith({
connectionId: 'remote-user',
path: '/api/git/status?path=%2Fsrv%2Fwork',
profile: 'default'
})
expect(api).toHaveBeenCalledWith({
body: { file: 'a.txt', path: '/srv/work' },
connectionId: 'remote-user',
method: 'POST',
path: '/api/git/review/stage',
profile: 'default'
})
})
it('sends mutations as POST bodies on a remote gateway', async () => {
$connection.set({ mode: 'remote' } as never)
await desktopGit()?.review.stage('/srv/work', 'a.txt')
expect(api).toHaveBeenCalledWith({
body: { file: 'a.txt', path: '/srv/work' },
method: 'POST',
path: '/api/git/review/stage'
})
expect(localGit.review.stage).not.toHaveBeenCalled()
})
// The ⌘⇧B "convert a branch into a worktree" flow (#81724): on a remote
// gateway both halves must reach the backend mirror — the picker's branch
// list (which now carries remote-tracking refs) and the worktree add that
// receives the picked `origin/…` name.
it('routes the convert-a-branch worktree flow through the backend on a remote gateway', async () => {
$connection.set({ mode: 'remote' } as never)
await expect(desktopGit()?.branchList('/srv/work')).resolves.toEqual([
{ checkedOut: false, isDefault: false, isRemote: true, name: 'origin/feature', worktreePath: null }
])
expect(api).toHaveBeenCalledWith({ path: '/api/git/branches?path=%2Fsrv%2Fwork' })
await desktopGit()?.worktreeAdd('/srv/work', { existingBranch: 'origin/feature' })
expect(api).toHaveBeenCalledWith({
body: { existingBranch: 'origin/feature', path: '/srv/work' },
method: 'POST',
path: '/api/git/worktree/add'
})
})
})