test: cover unhydrated SSH timestamp cleanup

This commit is contained in:
Jinjing
2026-06-23 23:29:58 -07:00
parent 26a9a59957
commit 580558dc6b
2 changed files with 25 additions and 6 deletions
@@ -668,6 +668,26 @@ describe('repo slice runtime routing', () => {
expect(runtimeEnvironmentCall).not.toHaveBeenCalled()
})
it('drops persisted visit timestamps for removed unhydrated SSH repos', async () => {
const store = createTestStore()
const sshWorktreeId = `${sshRepo.id}::/home/orca/wt`
const localWorktreeId = `${localRepo.id}::/local/wt`
store.setState({
repos: [sshRepo, localRepo],
activeRepoId: sshRepo.id,
lastVisitedAtByWorktreeId: {
[sshWorktreeId]: 100,
[localWorktreeId]: 200
}
})
await store.getState().removeProject(sshRepo.id)
expect(store.getState().repos).toEqual([localRepo])
expect(store.getState().lastVisitedAtByWorktreeId).toEqual({ [localWorktreeId]: 200 })
expect(reposRemove).toHaveBeenCalledWith({ repoId: sshRepo.id })
})
it('evicts GitHub caches for removed repos using repo id and legacy path keys', async () => {
const store = createTestStore()
store.setState({
+5 -6
View File
@@ -43,8 +43,8 @@ import { sanitizeRepoIcon } from '../../../../shared/repo-icon'
import { normalizeRepoBadgeColor } from '../../../../shared/repo-badge-color'
import { getProjectGroupSubtreeIds } from '../../../../shared/project-groups'
import { isPathInsideOrEqual } from '../../../../shared/cross-platform-path'
import { getRepoIdFromWorktreeId } from '../../../../shared/worktree-id'
import { selectProjectGroupRemovalTargets } from './project-group-removal-targets'
import { getRepoIdFromWorktreeId } from './worktree-helpers'
import { reconcileFetchedRepos } from './repo-identity-reconcile'
import { splitRepoReorderByHost } from './repo-reorder-host-split'
import {
@@ -2325,10 +2325,6 @@ export const createRepoSlice: StateCreator<AppState, [], [], RepoSlice> = (set,
const activeFileCleared = s.activeFileId
? s.openFiles.some((f) => f.id === s.activeFileId && worktreeIdSet.has(f.worktreeId))
: false
// Why: pruneLastVisitedTimestamps defers entries for repos missing
// from worktreesByRepo (treats them as not-yet-hydrated SSH repos).
// Drop this repo's timestamps explicitly so they cannot survive prune
// forever after the repo is removed.
const nextRepos = s.repos.filter((r) => !repoMatchesHostIdentity(r, projectId, ownerHostId))
// Why: when no sibling host still owns this repo id, drop every persisted
// timestamp for the repo's worktrees — including unhydrated SSH/remote ones
@@ -2338,7 +2334,10 @@ export const createRepoSlice: StateCreator<AppState, [], [], RepoSlice> = (set,
const repoIdFullyRemoved = !nextRepos.some((r) => r.id === projectId)
let nextLastVisitedAtByWorktreeId = s.lastVisitedAtByWorktreeId
for (const id of Object.keys(s.lastVisitedAtByWorktreeId)) {
if (worktreeIdSet.has(id) || (repoIdFullyRemoved && getRepoIdFromWorktreeId(id) === projectId)) {
if (
worktreeIdSet.has(id) ||
(repoIdFullyRemoved && getRepoIdFromWorktreeId(id) === projectId)
) {
if (nextLastVisitedAtByWorktreeId === s.lastVisitedAtByWorktreeId) {
nextLastVisitedAtByWorktreeId = { ...s.lastVisitedAtByWorktreeId }
}