Update engine tests so child_process mocks cover execFile alongside exec. - add execFile mock implementations and promisify support in branch/worktree tests that rely on child_process behavior - extend simpler child_process mocks in integration, sandbox, and worktree tests to export execFile stubs - keep existing exec and execSync mock behavior unchanged while restoring compatibility with code that now imports execFile Files changed: packages/engine/src/__tests__/branch-autocorrect.test.ts | 9 ++++++++- .../engine/src/__tests__/branch-conflicts-self-owned.test.ts | 9 ++++++++- packages/engine/src/__tests__/branch-conflicts.test.ts | 9 ++++++++- packages/engine/src/__tests__/integration-branch.test.ts | 1 + .../engine/src/__tests__/sandbox/bubblewrap-detect.test.ts | 1 + .../engine/src/__tests__/sandbox/sandbox-exec-backend.test.ts | 1 + .../engine/src/__tests__/sandbox/sandbox-exec-detect.test.ts | 1 + .../engine/src/__tests__/worktree-acquisition-backend.test.ts | 2 +- .../src/__tests__/worktree-acquisition-worktrunk.test.ts | 2 +- packages/engine/src/__tests__/worktree-backend.test.ts | 2 +- .../engine/src/__tests__/worktree-hooks-cross-platform.test.ts | 2 +- packages/engine/src/__tests__/worktree-pool.test.ts | 10 ++++++++-- packages/engine/src/__tests__/worktree-stale-lock.test.ts | 2 +- .../engine/src/__tests__/worktree-stale-registration.test.ts | 2 +- 14 files changed, 42 insertions(+), 11 deletions(-) Fusion-Task-Id: FN-6004 Fusion-Task-Lineage: f87fb103-fe5d-4fc9-a640-9991c06e6448
117 lines
4.1 KiB
TypeScript
117 lines
4.1 KiB
TypeScript
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
|
const { execMock, execSyncMock } = vi.hoisted(() => ({
|
|
execMock: vi.fn(),
|
|
execSyncMock: vi.fn(),
|
|
}));
|
|
|
|
vi.mock("node:child_process", () => ({
|
|
exec: execMock,
|
|
execSync: execSyncMock,
|
|
execFile: vi.fn(),
|
|
}));
|
|
|
|
import {
|
|
__resetIntegrationBranchCacheForTests,
|
|
INTEGRATION_BRANCH_FALLBACK,
|
|
resolveIntegrationBranch,
|
|
resolveIntegrationBranchSync,
|
|
} from "../integration-branch.js";
|
|
|
|
describe("integration-branch resolver", () => {
|
|
beforeEach(() => {
|
|
__resetIntegrationBranchCacheForTests();
|
|
execMock.mockReset();
|
|
execSyncMock.mockReset();
|
|
});
|
|
|
|
afterEach(() => {
|
|
__resetIntegrationBranchCacheForTests();
|
|
vi.restoreAllMocks();
|
|
});
|
|
|
|
it("integrationBranch override wins over baseBranch and origin/HEAD", async () => {
|
|
const resolved = await resolveIntegrationBranch("/repo", { integrationBranch: " trunk ", baseBranch: "develop" } as any);
|
|
|
|
expect(resolved).toBe("trunk");
|
|
expect(execMock).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("baseBranch wins over origin/HEAD", async () => {
|
|
const resolved = await resolveIntegrationBranch("/repo", { baseBranch: " develop " } as any);
|
|
|
|
expect(resolved).toBe("develop");
|
|
expect(execMock).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("strips refs/remotes/origin and origin prefixes", async () => {
|
|
execMock.mockImplementationOnce((_command: string, _opts: object, cb: (error: Error | null, result: { stdout: string }) => void) => {
|
|
cb(null, { stdout: "refs/remotes/origin/master\n" });
|
|
return {};
|
|
});
|
|
execMock.mockImplementationOnce((_command: string, _opts: object, cb: (error: Error | null, result: { stdout: string }) => void) => {
|
|
cb(null, { stdout: "origin/develop\n" });
|
|
return {};
|
|
});
|
|
|
|
const first = await resolveIntegrationBranch("/repo-a", {} as any);
|
|
const second = await resolveIntegrationBranch("/repo-b", {} as any);
|
|
|
|
expect(first).toBe("master");
|
|
expect(second).toBe("develop");
|
|
});
|
|
|
|
it("treats whitespace and empty settings as unset", async () => {
|
|
execMock.mockImplementation((_command: string, _opts: object, cb: (error: Error | null, result: { stdout: string }) => void) => {
|
|
cb(null, { stdout: "origin/master\n" });
|
|
return {};
|
|
});
|
|
|
|
const resolved = await resolveIntegrationBranch("/repo", { integrationBranch: " ", baseBranch: "" } as any);
|
|
|
|
expect(resolved).toBe("master");
|
|
});
|
|
|
|
it("falls back to main and warns once per rootDir", async () => {
|
|
execMock.mockImplementation((_command: string, _opts: object, cb: (error: Error | null, result: { stdout: string }) => void) => {
|
|
cb(new Error("no symbolic ref"), { stdout: "" });
|
|
return {};
|
|
});
|
|
const warn = vi.fn();
|
|
|
|
const first = await resolveIntegrationBranch("/repo", undefined, { logger: { warn } });
|
|
const second = await resolveIntegrationBranch("/repo", undefined, { logger: { warn } });
|
|
|
|
expect(first).toBe(INTEGRATION_BRANCH_FALLBACK);
|
|
expect(second).toBe(INTEGRATION_BRANCH_FALLBACK);
|
|
expect(warn).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it("sync and async variants match", async () => {
|
|
execMock.mockImplementation((_command: string, _opts: object, cb: (error: Error | null, result: { stdout: string }) => void) => {
|
|
cb(null, { stdout: "refs/remotes/origin/master\n" });
|
|
return {};
|
|
});
|
|
execSyncMock.mockReturnValue("origin/master\n");
|
|
|
|
const asyncResolved = await resolveIntegrationBranch("/repo", undefined);
|
|
const syncResolved = resolveIntegrationBranchSync("/repo", undefined);
|
|
|
|
expect(syncResolved).toEqual(asyncResolved);
|
|
expect(syncResolved).toBe("master");
|
|
});
|
|
|
|
it("swallows git failures and does not throw", async () => {
|
|
execMock.mockImplementation((_command: string, _opts: object, cb: (error: Error | null, result: { stdout: string }) => void) => {
|
|
cb(new Error("git failed"), { stdout: "" });
|
|
return {};
|
|
});
|
|
execSyncMock.mockImplementation(() => {
|
|
throw new Error("git failed");
|
|
});
|
|
|
|
await expect(resolveIntegrationBranch("/repo", undefined)).resolves.toBe(INTEGRATION_BRANCH_FALLBACK);
|
|
expect(() => resolveIntegrationBranchSync("/repo", undefined)).not.toThrow();
|
|
});
|
|
});
|