mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-14 10:41:23 +00:00
refactor: dedupe doctor codex oauth tests
This commit is contained in:
@@ -12,6 +12,75 @@ import "./doctor.fast-path-mocks.js";
|
||||
|
||||
let doctorCommand: typeof import("./doctor.js").doctorCommand;
|
||||
|
||||
const CODEX_PROVIDER_ID = "openai-codex";
|
||||
const CODEX_PROFILE_ID = "openai-codex:user@example.com";
|
||||
const CODEX_PROFILE_EMAIL = "user@example.com";
|
||||
|
||||
function configCodexOAuthProfile() {
|
||||
return {
|
||||
provider: CODEX_PROVIDER_ID,
|
||||
mode: "oauth",
|
||||
email: CODEX_PROFILE_EMAIL,
|
||||
};
|
||||
}
|
||||
|
||||
function storedCodexOAuthProfile() {
|
||||
return {
|
||||
type: "oauth",
|
||||
provider: CODEX_PROVIDER_ID,
|
||||
access: "access-token",
|
||||
refresh: "refresh-token",
|
||||
expires: Date.now() + 60_000,
|
||||
email: CODEX_PROFILE_EMAIL,
|
||||
};
|
||||
}
|
||||
|
||||
function mockAuthProfileStore(profiles: Record<string, unknown> = {}): void {
|
||||
ensureAuthProfileStore.mockReturnValue({
|
||||
version: 1,
|
||||
profiles,
|
||||
});
|
||||
}
|
||||
|
||||
function mockCodexProviderSnapshot(params: {
|
||||
provider: Record<string, unknown>;
|
||||
withConfigOAuth?: boolean;
|
||||
}): void {
|
||||
mockDoctorConfigSnapshot({
|
||||
config: {
|
||||
models: {
|
||||
providers: {
|
||||
[CODEX_PROVIDER_ID]: params.provider,
|
||||
},
|
||||
},
|
||||
...(params.withConfigOAuth
|
||||
? {
|
||||
auth: {
|
||||
profiles: {
|
||||
[CODEX_PROFILE_ID]: configCodexOAuthProfile(),
|
||||
},
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async function runDoctorNonInteractive(): Promise<void> {
|
||||
await doctorCommand(createDoctorRuntime(), {
|
||||
nonInteractive: true,
|
||||
workspaceSuggestions: false,
|
||||
});
|
||||
}
|
||||
|
||||
function hasCodexOAuthWarning(messageIncludes?: string): boolean {
|
||||
return terminalNoteMock.mock.calls.some(
|
||||
([message, title]) =>
|
||||
title === "Codex OAuth" &&
|
||||
(messageIncludes === undefined || String(message).includes(messageIncludes)),
|
||||
);
|
||||
}
|
||||
|
||||
describe("doctor command", () => {
|
||||
beforeEach(async () => {
|
||||
doctorCommand = await loadDoctorCommandForTest({
|
||||
@@ -70,223 +139,98 @@ describe("doctor command", () => {
|
||||
});
|
||||
|
||||
it("warns when a legacy openai-codex provider override shadows configured Codex OAuth", async () => {
|
||||
mockDoctorConfigSnapshot({
|
||||
config: {
|
||||
models: {
|
||||
providers: {
|
||||
"openai-codex": {
|
||||
api: "openai-responses",
|
||||
baseUrl: "https://api.openai.com/v1",
|
||||
},
|
||||
},
|
||||
},
|
||||
auth: {
|
||||
profiles: {
|
||||
"openai-codex:user@example.com": {
|
||||
provider: "openai-codex",
|
||||
mode: "oauth",
|
||||
email: "user@example.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
mockCodexProviderSnapshot({
|
||||
provider: {
|
||||
api: "openai-responses",
|
||||
baseUrl: "https://api.openai.com/v1",
|
||||
},
|
||||
withConfigOAuth: true,
|
||||
});
|
||||
ensureAuthProfileStore.mockReturnValue({
|
||||
version: 1,
|
||||
profiles: {},
|
||||
});
|
||||
mockAuthProfileStore();
|
||||
|
||||
await doctorCommand(createDoctorRuntime(), {
|
||||
nonInteractive: true,
|
||||
workspaceSuggestions: false,
|
||||
});
|
||||
await runDoctorNonInteractive();
|
||||
|
||||
const warned = terminalNoteMock.mock.calls.some(
|
||||
([message, title]) =>
|
||||
title === "Codex OAuth" && String(message).includes("models.providers.openai-codex"),
|
||||
);
|
||||
expect(warned).toBe(true);
|
||||
expect(hasCodexOAuthWarning("models.providers.openai-codex")).toBe(true);
|
||||
});
|
||||
|
||||
it("warns when a legacy openai-codex provider override shadows stored Codex OAuth", async () => {
|
||||
mockDoctorConfigSnapshot({
|
||||
config: {
|
||||
models: {
|
||||
providers: {
|
||||
"openai-codex": {
|
||||
api: "openai-responses",
|
||||
baseUrl: "https://api.openai.com/v1",
|
||||
},
|
||||
},
|
||||
},
|
||||
mockCodexProviderSnapshot({
|
||||
provider: {
|
||||
api: "openai-responses",
|
||||
baseUrl: "https://api.openai.com/v1",
|
||||
},
|
||||
});
|
||||
ensureAuthProfileStore.mockReturnValue({
|
||||
version: 1,
|
||||
profiles: {
|
||||
"openai-codex:user@example.com": {
|
||||
type: "oauth",
|
||||
provider: "openai-codex",
|
||||
access: "access-token",
|
||||
refresh: "refresh-token",
|
||||
expires: Date.now() + 60_000,
|
||||
email: "user@example.com",
|
||||
},
|
||||
},
|
||||
mockAuthProfileStore({
|
||||
[CODEX_PROFILE_ID]: storedCodexOAuthProfile(),
|
||||
});
|
||||
|
||||
await doctorCommand(createDoctorRuntime(), {
|
||||
nonInteractive: true,
|
||||
workspaceSuggestions: false,
|
||||
});
|
||||
await runDoctorNonInteractive();
|
||||
|
||||
const warned = terminalNoteMock.mock.calls.some(
|
||||
([message, title]) =>
|
||||
title === "Codex OAuth" && String(message).includes("models.providers.openai-codex"),
|
||||
);
|
||||
expect(warned).toBe(true);
|
||||
expect(hasCodexOAuthWarning("models.providers.openai-codex")).toBe(true);
|
||||
});
|
||||
|
||||
it("warns when an inline openai-codex model keeps the legacy OpenAI transport", async () => {
|
||||
mockDoctorConfigSnapshot({
|
||||
config: {
|
||||
models: {
|
||||
providers: {
|
||||
"openai-codex": {
|
||||
models: [
|
||||
{
|
||||
id: "gpt-5.4",
|
||||
api: "openai-responses",
|
||||
},
|
||||
],
|
||||
},
|
||||
mockCodexProviderSnapshot({
|
||||
provider: {
|
||||
models: [
|
||||
{
|
||||
id: "gpt-5.4",
|
||||
api: "openai-responses",
|
||||
},
|
||||
},
|
||||
auth: {
|
||||
profiles: {
|
||||
"openai-codex:user@example.com": {
|
||||
provider: "openai-codex",
|
||||
mode: "oauth",
|
||||
email: "user@example.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
withConfigOAuth: true,
|
||||
});
|
||||
ensureAuthProfileStore.mockReturnValue({
|
||||
version: 1,
|
||||
profiles: {},
|
||||
});
|
||||
mockAuthProfileStore();
|
||||
|
||||
await doctorCommand(createDoctorRuntime(), {
|
||||
nonInteractive: true,
|
||||
workspaceSuggestions: false,
|
||||
});
|
||||
await runDoctorNonInteractive();
|
||||
|
||||
const warned = terminalNoteMock.mock.calls.some(
|
||||
([message, title]) =>
|
||||
title === "Codex OAuth" && String(message).includes("legacy transport override"),
|
||||
);
|
||||
expect(warned).toBe(true);
|
||||
expect(hasCodexOAuthWarning("legacy transport override")).toBe(true);
|
||||
});
|
||||
|
||||
it("does not warn for a custom openai-codex proxy override", async () => {
|
||||
mockDoctorConfigSnapshot({
|
||||
config: {
|
||||
models: {
|
||||
providers: {
|
||||
"openai-codex": {
|
||||
api: "openai-responses",
|
||||
baseUrl: "https://custom.example.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
auth: {
|
||||
profiles: {
|
||||
"openai-codex:user@example.com": {
|
||||
provider: "openai-codex",
|
||||
mode: "oauth",
|
||||
email: "user@example.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
mockCodexProviderSnapshot({
|
||||
provider: {
|
||||
api: "openai-responses",
|
||||
baseUrl: "https://custom.example.com",
|
||||
},
|
||||
withConfigOAuth: true,
|
||||
});
|
||||
ensureAuthProfileStore.mockReturnValue({
|
||||
version: 1,
|
||||
profiles: {},
|
||||
});
|
||||
mockAuthProfileStore();
|
||||
|
||||
await doctorCommand(createDoctorRuntime(), {
|
||||
nonInteractive: true,
|
||||
workspaceSuggestions: false,
|
||||
});
|
||||
await runDoctorNonInteractive();
|
||||
|
||||
const warned = terminalNoteMock.mock.calls.some(([, title]) => title === "Codex OAuth");
|
||||
expect(warned).toBe(false);
|
||||
expect(hasCodexOAuthWarning()).toBe(false);
|
||||
});
|
||||
|
||||
it("does not warn for header-only openai-codex overrides", async () => {
|
||||
mockDoctorConfigSnapshot({
|
||||
config: {
|
||||
models: {
|
||||
providers: {
|
||||
"openai-codex": {
|
||||
baseUrl: "https://custom.example.com",
|
||||
headers: { "X-Custom-Auth": "token-123" },
|
||||
models: [{ id: "gpt-5.4" }],
|
||||
},
|
||||
},
|
||||
},
|
||||
auth: {
|
||||
profiles: {
|
||||
"openai-codex:user@example.com": {
|
||||
provider: "openai-codex",
|
||||
mode: "oauth",
|
||||
email: "user@example.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
mockCodexProviderSnapshot({
|
||||
provider: {
|
||||
baseUrl: "https://custom.example.com",
|
||||
headers: { "X-Custom-Auth": "token-123" },
|
||||
models: [{ id: "gpt-5.4" }],
|
||||
},
|
||||
withConfigOAuth: true,
|
||||
});
|
||||
ensureAuthProfileStore.mockReturnValue({
|
||||
version: 1,
|
||||
profiles: {},
|
||||
});
|
||||
mockAuthProfileStore();
|
||||
|
||||
await doctorCommand(createDoctorRuntime(), {
|
||||
nonInteractive: true,
|
||||
workspaceSuggestions: false,
|
||||
});
|
||||
await runDoctorNonInteractive();
|
||||
|
||||
const warned = terminalNoteMock.mock.calls.some(([, title]) => title === "Codex OAuth");
|
||||
expect(warned).toBe(false);
|
||||
expect(hasCodexOAuthWarning()).toBe(false);
|
||||
});
|
||||
|
||||
it("does not warn about an openai-codex provider override without Codex OAuth", async () => {
|
||||
mockDoctorConfigSnapshot({
|
||||
config: {
|
||||
models: {
|
||||
providers: {
|
||||
"openai-codex": {
|
||||
api: "openai-responses",
|
||||
baseUrl: "https://api.openai.com/v1",
|
||||
},
|
||||
},
|
||||
},
|
||||
mockCodexProviderSnapshot({
|
||||
provider: {
|
||||
api: "openai-responses",
|
||||
baseUrl: "https://api.openai.com/v1",
|
||||
},
|
||||
});
|
||||
ensureAuthProfileStore.mockReturnValue({
|
||||
version: 1,
|
||||
profiles: {},
|
||||
});
|
||||
mockAuthProfileStore();
|
||||
|
||||
await doctorCommand(createDoctorRuntime(), {
|
||||
nonInteractive: true,
|
||||
workspaceSuggestions: false,
|
||||
});
|
||||
await runDoctorNonInteractive();
|
||||
|
||||
const warned = terminalNoteMock.mock.calls.some(([, title]) => title === "Codex OAuth");
|
||||
expect(warned).toBe(false);
|
||||
expect(hasCodexOAuthWarning()).toBe(false);
|
||||
});
|
||||
|
||||
it("skips gateway auth warning when OPENCLAW_GATEWAY_TOKEN is set", async () => {
|
||||
|
||||
Reference in New Issue
Block a user