Squashed 'third_party/pi/' content from commit d981de122
git-subtree-dir: third_party/pi git-subtree-split: d981de1229ef899957bbe968bc8dcda02a21f477
This commit is contained in:
131
packages/coding-agent/test/version-check.test.ts
Normal file
131
packages/coding-agent/test/version-check.test.ts
Normal file
@@ -0,0 +1,131 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import {
|
||||
checkForNewPiVersion,
|
||||
comparePackageVersions,
|
||||
formatVersionCheckError,
|
||||
getLatestPiRelease,
|
||||
getLatestPiVersion,
|
||||
isNewerPackageVersion,
|
||||
} from "../src/utils/version-check.ts";
|
||||
import { allowNetwork } from "./test-network-env.ts";
|
||||
|
||||
const originalSkipVersionCheck = process.env.PI_SKIP_VERSION_CHECK;
|
||||
|
||||
beforeEach(() => {
|
||||
allowNetwork();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.unstubAllGlobals();
|
||||
if (originalSkipVersionCheck === undefined) {
|
||||
delete process.env.PI_SKIP_VERSION_CHECK;
|
||||
} else {
|
||||
process.env.PI_SKIP_VERSION_CHECK = originalSkipVersionCheck;
|
||||
}
|
||||
});
|
||||
|
||||
describe("version checks", () => {
|
||||
it("compares package versions", () => {
|
||||
expect(comparePackageVersions("0.70.6", "0.70.5")).toBeGreaterThan(0);
|
||||
expect(comparePackageVersions("0.70.5", "0.70.5")).toBe(0);
|
||||
expect(comparePackageVersions("0.70.4", "0.70.5")).toBeLessThan(0);
|
||||
expect(comparePackageVersions("5.0.0-beta.20", "5.0.0-beta.9")).toBeGreaterThan(0);
|
||||
expect(isNewerPackageVersion("0.70.5", "0.70.5")).toBe(false);
|
||||
expect(isNewerPackageVersion("0.70.6", "0.70.5")).toBe(true);
|
||||
});
|
||||
|
||||
it("returns only newer versions", async () => {
|
||||
const fetchMock = vi.fn(async () => Response.json({ version: "1.2.3" }));
|
||||
vi.stubGlobal("fetch", fetchMock);
|
||||
|
||||
await expect(checkForNewPiVersion("1.2.3")).resolves.toBeUndefined();
|
||||
await expect(checkForNewPiVersion("1.2.2")).resolves.toEqual({ version: "1.2.3" });
|
||||
});
|
||||
|
||||
it("uses the pi.dev version check api with a pi user agent", async () => {
|
||||
const fetchMock = vi.fn(async () => Response.json({ version: "1.2.4" }));
|
||||
vi.stubGlobal("fetch", fetchMock);
|
||||
|
||||
await expect(getLatestPiVersion("1.2.3")).resolves.toBe("1.2.4");
|
||||
expect(fetchMock).toHaveBeenCalledWith(
|
||||
"https://pi.dev/api/latest-version",
|
||||
expect.objectContaining({
|
||||
headers: expect.objectContaining({
|
||||
"User-Agent": expect.stringMatching(/^pi\/1\.2\.3 /),
|
||||
accept: "application/json",
|
||||
}),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("retries a transient version request when explicitly requested", async () => {
|
||||
const fetchMock = vi
|
||||
.fn()
|
||||
.mockRejectedValueOnce(new Error("fetch failed"))
|
||||
.mockRejectedValueOnce(new Error("fetch failed"))
|
||||
.mockResolvedValueOnce(Response.json({ version: "1.2.4" }));
|
||||
vi.stubGlobal("fetch", fetchMock);
|
||||
|
||||
await expect(getLatestPiRelease("1.2.3", { retry: true })).resolves.toEqual({ version: "1.2.4" });
|
||||
expect(fetchMock).toHaveBeenCalledTimes(3);
|
||||
});
|
||||
|
||||
it("keeps automatic version checks to one request", async () => {
|
||||
const fetchMock = vi.fn().mockRejectedValue(new Error("fetch failed"));
|
||||
vi.stubGlobal("fetch", fetchMock);
|
||||
|
||||
await expect(checkForNewPiVersion("1.2.3")).resolves.toBeUndefined();
|
||||
expect(fetchMock).toHaveBeenCalledOnce();
|
||||
});
|
||||
|
||||
it("formats nested network error details", () => {
|
||||
const error = new Error("fetch failed", {
|
||||
cause: new AggregateError([
|
||||
Object.assign(new Error("connect timeout"), { code: "ETIMEDOUT" }),
|
||||
Object.assign(new Error("network unreachable"), { code: "ENETUNREACH" }),
|
||||
]),
|
||||
});
|
||||
|
||||
expect(formatVersionCheckError(error)).toBe("fetch failed (ETIMEDOUT, ENETUNREACH)");
|
||||
});
|
||||
|
||||
it("returns the active package metadata from the version check api", async () => {
|
||||
const fetchMock = vi.fn(async () =>
|
||||
Response.json({
|
||||
packageName: "@new-scope/pi",
|
||||
version: "1.2.4",
|
||||
}),
|
||||
);
|
||||
vi.stubGlobal("fetch", fetchMock);
|
||||
|
||||
await expect(getLatestPiRelease("1.2.3")).resolves.toEqual({
|
||||
packageName: "@new-scope/pi",
|
||||
version: "1.2.4",
|
||||
});
|
||||
});
|
||||
|
||||
it("returns update notes from the version check api", async () => {
|
||||
const fetchMock = vi.fn(async () => Response.json({ note: " **Read this** ", version: "1.2.4" }));
|
||||
vi.stubGlobal("fetch", fetchMock);
|
||||
|
||||
await expect(getLatestPiRelease("1.2.3")).resolves.toEqual({ note: "**Read this**", version: "1.2.4" });
|
||||
});
|
||||
|
||||
it("skips automatic api calls when version checks are disabled", async () => {
|
||||
process.env.PI_SKIP_VERSION_CHECK = "1";
|
||||
const fetchMock = vi.fn();
|
||||
vi.stubGlobal("fetch", fetchMock);
|
||||
|
||||
await expect(checkForNewPiVersion("1.2.3")).resolves.toBeUndefined();
|
||||
expect(fetchMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("allows direct api calls when automatic version checks are disabled", async () => {
|
||||
process.env.PI_SKIP_VERSION_CHECK = "1";
|
||||
const fetchMock = vi.fn(async () => Response.json({ version: "1.2.4" }));
|
||||
vi.stubGlobal("fetch", fetchMock);
|
||||
|
||||
await expect(getLatestPiVersion("1.2.3")).resolves.toBe("1.2.4");
|
||||
expect(fetchMock).toHaveBeenCalledOnce();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user