
























@@ -1,4 +1,15 @@
1-import { afterEach, describe, expect, it, vi } from "vitest";
1+import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2+3+const { readCodexCliCredentialsCachedMock } = vi.hoisted(() => ({
4+readCodexCliCredentialsCachedMock: vi.fn(() => null),
5+}));
6+7+vi.mock("./cli-credentials.js", () => ({
8+readCodexCliCredentialsCached: readCodexCliCredentialsCachedMock,
9+readMiniMaxCliCredentialsCached: () => null,
10+resetCliCredentialCachesForTest: () => undefined,
11+}));
12+213import {
314buildAuthHealthSummary,
415DEFAULT_OAUTH_WARN_MS,
@@ -16,6 +27,11 @@ describe("buildAuthHealthSummary", () => {
1627vi.restoreAllMocks();
1728});
182930+beforeEach(() => {
31+readCodexCliCredentialsCachedMock.mockReset();
32+readCodexCliCredentialsCachedMock.mockReturnValue(null);
33+});
34+1935it("classifies OAuth and API key profiles", () => {
2036vi.spyOn(Date, "now").mockReturnValue(now);
2137const store = {
@@ -58,13 +74,12 @@ describe("buildAuthHealthSummary", () => {
5874const statuses = profileStatuses(summary);
59756076expect(statuses["anthropic:ok"]).toBe("ok");
61-// OAuth credentials with refresh tokens are auto-renewable, so they report "ok"
62-expect(statuses["anthropic:expiring"]).toBe("ok");
63-expect(statuses["anthropic:expired"]).toBe("ok");
77+expect(statuses["anthropic:expiring"]).toBe("expiring");
78+expect(statuses["anthropic:expired"]).toBe("expired");
6479expect(statuses["anthropic:api"]).toBe("static");
65806681const provider = summary.providers.find((entry) => entry.provider === "anthropic");
67-expect(provider?.status).toBe("ok");
82+expect(provider?.status).toBe("expired");
6883});
69847085it("reports expired for OAuth without a refresh token", () => {
@@ -92,6 +107,38 @@ describe("buildAuthHealthSummary", () => {
92107expect(statuses["google:no-refresh"]).toBe("expired");
93108});
94109110+it("prefers fresher imported external OAuth credentials when reporting health", () => {
111+vi.spyOn(Date, "now").mockReturnValue(now);
112+readCodexCliCredentialsCachedMock.mockReturnValue({
113+type: "oauth",
114+provider: "openai-codex",
115+access: "fresh-cli-access",
116+refresh: "fresh-cli-refresh",
117+expires: now + DEFAULT_OAUTH_WARN_MS + 60_000,
118+accountId: "acct-cli",
119+});
120+const store = {
121+version: 1,
122+profiles: {
123+"openai-codex:default": {
124+type: "oauth" as const,
125+provider: "openai-codex",
126+access: "expired-access",
127+refresh: "expired-refresh",
128+expires: now - 10_000,
129+},
130+},
131+};
132+133+const summary = buildAuthHealthSummary({
134+ store,
135+warnAfterMs: DEFAULT_OAUTH_WARN_MS,
136+});
137+138+const statuses = profileStatuses(summary);
139+expect(statuses["openai-codex:default"]).toBe("ok");
140+});
141+95142it("marks token profiles with invalid expires as missing with reason code", () => {
96143vi.spyOn(Date, "now").mockReturnValue(now);
97144const store = {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。