fix(git): harden nested repository discovery
- discard an in-flight discovery when the runtime switches, mirroring the isRequestCurrent pattern, so a late completion cannot repopulate the cleared map and suppress a fresh scan - treat a 501 from /api/fs/git-dirs as an explicit 'unsupported' marker instead of a generic failure; the VS Code webview now answers the route with unsupportedWebRouteResponse so non-repo roots show the honest not-a-repository state without a futile Retry
This commit is contained in:
@@ -1,8 +1,22 @@
|
||||
import { beforeEach, describe, expect, test } from 'bun:test';
|
||||
import { beforeEach, describe, expect, mock, test } from 'bun:test';
|
||||
import type { GitStatus } from '@/lib/api/types';
|
||||
import { useGitStore } from './useGitStore';
|
||||
import { getRuntimeKey } from '@/lib/runtime-switch';
|
||||
|
||||
// The real transport has no server in tests and fails as a generic error.
|
||||
// Tests that exercise other failure modes swap this implementation; the
|
||||
// default keeps every pre-existing expectation (generic failure → null).
|
||||
const listGitDirectoriesControl: { impl: (root: string) => Promise<string[]> } = {
|
||||
impl: async () => {
|
||||
throw new Error('network unavailable');
|
||||
},
|
||||
};
|
||||
class TestGitDirectoriesUnsupportedError extends Error {}
|
||||
mock.module('@/lib/gitApiHttp', () => ({
|
||||
GitDirectoriesUnsupportedError: TestGitDirectoriesUnsupportedError,
|
||||
listGitDirectories: (root: string) => listGitDirectoriesControl.impl(root),
|
||||
}));
|
||||
|
||||
type Deferred<T> = {
|
||||
promise: Promise<T>;
|
||||
resolve: (value: T) => void;
|
||||
@@ -338,6 +352,9 @@ describe('useGitStore', () => {
|
||||
|
||||
describe('useGitStore nested repository discovery', () => {
|
||||
beforeEach(() => {
|
||||
listGitDirectoriesControl.impl = async () => {
|
||||
throw new Error('network unavailable');
|
||||
};
|
||||
useGitStore.getState().resetForRuntimeSwitch(getRuntimeKey());
|
||||
});
|
||||
|
||||
@@ -379,12 +396,47 @@ describe('useGitStore nested repository discovery', () => {
|
||||
expect(useGitStore.getState().nestedReposByRoot.size).toBe(0);
|
||||
});
|
||||
|
||||
test('discards an in-flight discovery result when the runtime switches', async () => {
|
||||
const stale = useGitStore.getState().ensureNestedRepos('/root-a');
|
||||
useGitStore.getState().resetForRuntimeSwitch('runtime-b');
|
||||
await stale;
|
||||
|
||||
// The old runtime's late completion must not repopulate the cleared map.
|
||||
expect(useGitStore.getState().nestedReposByRoot.has('/root-a')).toBe(false);
|
||||
|
||||
// Discovery started under the new runtime still commits normally.
|
||||
await useGitStore.getState().ensureNestedRepos('/root-a');
|
||||
expect(useGitStore.getState().nestedReposByRoot.get('/root-a')).toBeNull();
|
||||
});
|
||||
|
||||
test('marks discovery failure as a failed marker, not an empty success', async () => {
|
||||
await useGitStore.getState().ensureNestedRepos('/root-a');
|
||||
|
||||
expect(useGitStore.getState().nestedReposByRoot.get('/root-a')).toBeNull();
|
||||
});
|
||||
|
||||
test('marks a 501 runtime as unsupported instead of failed', async () => {
|
||||
listGitDirectoriesControl.impl = async () => {
|
||||
throw new TestGitDirectoriesUnsupportedError();
|
||||
};
|
||||
|
||||
await useGitStore.getState().ensureNestedRepos('/root-a');
|
||||
|
||||
expect(useGitStore.getState().nestedReposByRoot.get('/root-a')).toBe('unsupported');
|
||||
});
|
||||
|
||||
test('unsupported does not clobber a previous successful discovery', async () => {
|
||||
listGitDirectoriesControl.impl = async () => ['/root-a/one'];
|
||||
await useGitStore.getState().ensureNestedRepos('/root-a');
|
||||
|
||||
listGitDirectoriesControl.impl = async () => {
|
||||
throw new TestGitDirectoriesUnsupportedError();
|
||||
};
|
||||
await useGitStore.getState().ensureNestedRepos('/root-a', { force: true });
|
||||
|
||||
expect(useGitStore.getState().nestedReposByRoot.get('/root-a')).toEqual(['/root-a/one']);
|
||||
});
|
||||
|
||||
test('dedupes concurrent discovery runs for the same root', async () => {
|
||||
const first = useGitStore.getState().ensureNestedRepos('/root-a');
|
||||
const second = useGitStore.getState().ensureNestedRepos('/root-a');
|
||||
|
||||
Reference in New Issue
Block a user