From c976e2e5a5b1ce4f8b2b2787c92186ff94339f85 Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Wed, 23 Sep 2026 23:25:30 +0200 Subject: [PATCH] test(server): wait for repository observation before asserting ref refresh (#5303) * test(server): wait for repository observation before asserting ref refresh The first checkout facts read can begin before the metadata watcher registers. The test sent an event through an optional watcher lookup at that point and silently dropped it, so a slow setup left only the initial snapshot. Hold the first read to reproduce the ordering and wait for observation setup and the initial refresh before emitting the ref event. * test(server): isolate ref refresh from background fetch An asynchronous background fetch could also schedule a structural refresh or populate the known-ref set. Give this test an empty fetch result and wait for that fetch to complete so the second facts read proves the injected watcher event caused it. * test(server): require the registered repository watcher in the assertion --- .../workspace-git-service.observation.test.ts | 47 +++++++++++++------ 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/packages/server/src/server/workspace-git-service.observation.test.ts b/packages/server/src/server/workspace-git-service.observation.test.ts index f5bfbc344c..8285304570 100644 --- a/packages/server/src/server/workspace-git-service.observation.test.ts +++ b/packages/server/src/server/workspace-git-service.observation.test.ts @@ -996,27 +996,44 @@ describe("WorkspaceGitService checkout observation", () => { test("origin/main refreshes a main checkout without configured upstream", async () => { const watcher = createWatcherHarness(); - const getCheckoutSnapshotFacts = vi.fn(async (cwd: string) => ({ - ...createCheckoutFacts(cwd), - currentBranch: "main", - remoteUrl: REMOTE_URL, - resolvedBaseRef: "main", - comparisonBaseRef: null, - branchRemoteName: null, - branchMergeRef: null, - upstreamStatus: null, + const releaseInitialFacts = createDeferred(); + const getCheckoutSnapshotFacts = vi.fn(async (cwd: string) => { + await releaseInitialFacts.promise; + return { + ...createCheckoutFacts(cwd), + currentBranch: "main", + remoteUrl: REMOTE_URL, + resolvedBaseRef: "main", + comparisonBaseRef: null, + branchRemoteName: null, + branchMergeRef: null, + upstreamStatus: null, + }; + }); + const runGitFetch = vi.fn(async () => ({ + changes: [], + nonRemoteRefsChanged: false, + error: null, })); - const service = createService(watcher, { getCheckoutSnapshotFacts }); + const service = createService(watcher, { getCheckoutSnapshotFacts, runGitFetch }); const subscription = service.registerWorkspace({ cwd: REPO_CWD }, vi.fn()); await vi.waitFor(() => { expect(getCheckoutSnapshotFacts).toHaveBeenCalledTimes(1); }); - watcher.records - .find((record) => record.directory === GIT_DIR) - ?.callback(null, [ - { path: path.join(GIT_DIR, "refs", "remotes", "origin", "main"), type: "update" }, - ]); + releaseInitialFacts.resolve(); + await vi.waitFor(() => { + expect(getWatcherRecordsForDirectory(watcher, GIT_DIR)).toHaveLength(1); + expect(service.getMetrics().workspaceRefreshInFlightCount).toBe(0); + expect(service.getMetrics().workspaceObservationSetupInFlightCount).toBe(0); + expect(service.getMetrics().fetchInFlightCount).toBe(0); + expect(runGitFetch).toHaveBeenCalledTimes(1); + }); + expect(getCheckoutSnapshotFacts).toHaveBeenCalledTimes(1); + const repoWatcher = getWatcherRecordsForDirectory(watcher, GIT_DIR)[0]!; + repoWatcher.callback(null, [ + { path: path.join(GIT_DIR, "refs", "remotes", "origin", "main"), type: "update" }, + ]); await vi.advanceTimersByTimeAsync(1_000); await vi.waitFor(() => { expect(getCheckoutSnapshotFacts).toHaveBeenCalledTimes(2);