Files
xo-cli/tests/updater/git-update-service.test.ts
T
2026-09-08 17:41:27 +00:00

98 lines
3.2 KiB
TypeScript

import path from "node:path";
import { describe, expect, test } from "vitest";
import {
GitUpdateService,
UPDATE_REMOTE_URL,
type CommandResult,
type CommandRunner,
} from "../../src/updater/git-update-service.js";
function result(stdout = "", code = 0, stderr = ""): CommandResult {
return { code, stdout, stderr };
}
function fakeRunner(responses: Map<string, CommandResult>): CommandRunner {
return async (command, args) =>
responses.get(`${command} ${args.join(" ")}`) ??
result("", 1, "unexpected command");
}
describe("GitUpdateService", () => {
test("checks the currently checked-out branch", async () => {
const root = path.resolve(".");
const runner = fakeRunner(
new Map([
["git branch --show-current", result("feature/demo\n")],
[
`git fetch --quiet ${UPDATE_REMOTE_URL} +refs/heads/feature/demo:refs/remotes/xo-updater/feature/demo`,
result(),
],
["git rev-parse HEAD", result("aaa\n")],
["git rev-parse refs/remotes/xo-updater/feature/demo", result("bbb\n")],
["git status --porcelain", result()],
["git merge-base --is-ancestor aaa bbb", result()],
["git log -1 --format=%s bbb", result("Useful update\n")],
]),
);
const update = await new GitUpdateService(root, runner).check();
expect(update).toMatchObject({
status: "available",
branch: "feature/demo",
currentCommit: "aaa",
targetCommit: "bbb",
canApply: true,
});
});
test("reports an available update but blocks applying over local changes", async () => {
const root = path.resolve(".");
const runner = fakeRunner(
new Map([
["git branch --show-current", result("main\n")],
[
`git fetch --quiet ${UPDATE_REMOTE_URL} +refs/heads/main:refs/remotes/xo-updater/main`,
result(),
],
["git rev-parse HEAD", result("aaa\n")],
["git rev-parse refs/remotes/xo-updater/main", result("bbb\n")],
["git status --porcelain", result(" M src/example.ts\n")],
["git merge-base --is-ancestor aaa bbb", result()],
["git log -1 --format=%s bbb", result("Update\n")],
]),
);
const update = await new GitUpdateService(root, runner).check();
expect(update).toMatchObject({ status: "available", canApply: false });
});
test("does not replace commits when the local branch is ahead", async () => {
const root = path.resolve(".");
const runner = fakeRunner(
new Map([
["git branch --show-current", result("main\n")],
[
`git fetch --quiet ${UPDATE_REMOTE_URL} +refs/heads/main:refs/remotes/xo-updater/main`,
result(),
],
["git rev-parse HEAD", result("bbb\n")],
["git rev-parse refs/remotes/xo-updater/main", result("aaa\n")],
["git status --porcelain", result()],
["git merge-base --is-ancestor bbb aaa", result("", 1)],
["git merge-base --is-ancestor aaa bbb", result()],
]),
);
await expect(
new GitUpdateService(root, runner).check(),
).resolves.toMatchObject({
status: "up-to-date",
branch: "main",
currentCommit: "bbb",
});
});
});