mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-10 03:52:42 +00:00
Auth: land codex oauth onboarding flow (#15406)
This commit is contained in:
98
src/commands/openai-codex-oauth.test.ts
Normal file
98
src/commands/openai-codex-oauth.test.ts
Normal file
@@ -0,0 +1,98 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { RuntimeEnv } from "../runtime.js";
|
||||
import type { WizardPrompter } from "../wizard/prompts.js";
|
||||
|
||||
const mocks = vi.hoisted(() => ({
|
||||
loginOpenAICodex: vi.fn(),
|
||||
createVpsAwareOAuthHandlers: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("@mariozechner/pi-ai", () => ({
|
||||
loginOpenAICodex: mocks.loginOpenAICodex,
|
||||
}));
|
||||
|
||||
vi.mock("./oauth-flow.js", () => ({
|
||||
createVpsAwareOAuthHandlers: mocks.createVpsAwareOAuthHandlers,
|
||||
}));
|
||||
|
||||
import { loginOpenAICodexOAuth } from "./openai-codex-oauth.js";
|
||||
|
||||
function createPrompter() {
|
||||
const spin = { update: vi.fn(), stop: vi.fn() };
|
||||
const prompter: Pick<WizardPrompter, "note" | "progress"> = {
|
||||
note: vi.fn(async () => {}),
|
||||
progress: vi.fn(() => spin),
|
||||
};
|
||||
return { prompter: prompter as unknown as WizardPrompter, spin };
|
||||
}
|
||||
|
||||
function createRuntime(): RuntimeEnv {
|
||||
return {
|
||||
log: vi.fn(),
|
||||
error: vi.fn(),
|
||||
exit: vi.fn((code: number) => {
|
||||
throw new Error(`exit:${code}`);
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
describe("loginOpenAICodexOAuth", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("returns credentials on successful oauth login", async () => {
|
||||
const creds = {
|
||||
provider: "openai-codex" as const,
|
||||
access: "access-token",
|
||||
refresh: "refresh-token",
|
||||
expires: Date.now() + 60_000,
|
||||
email: "user@example.com",
|
||||
};
|
||||
mocks.createVpsAwareOAuthHandlers.mockReturnValue({
|
||||
onAuth: vi.fn(),
|
||||
onPrompt: vi.fn(),
|
||||
});
|
||||
mocks.loginOpenAICodex.mockResolvedValue(creds);
|
||||
|
||||
const { prompter, spin } = createPrompter();
|
||||
const runtime = createRuntime();
|
||||
const result = await loginOpenAICodexOAuth({
|
||||
prompter,
|
||||
runtime,
|
||||
isRemote: false,
|
||||
openUrl: async () => {},
|
||||
});
|
||||
|
||||
expect(result).toEqual(creds);
|
||||
expect(mocks.loginOpenAICodex).toHaveBeenCalledOnce();
|
||||
expect(spin.stop).toHaveBeenCalledWith("OpenAI OAuth complete");
|
||||
expect(runtime.error).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("reports oauth errors and rethrows", async () => {
|
||||
mocks.createVpsAwareOAuthHandlers.mockReturnValue({
|
||||
onAuth: vi.fn(),
|
||||
onPrompt: vi.fn(),
|
||||
});
|
||||
mocks.loginOpenAICodex.mockRejectedValue(new Error("oauth failed"));
|
||||
|
||||
const { prompter, spin } = createPrompter();
|
||||
const runtime = createRuntime();
|
||||
await expect(
|
||||
loginOpenAICodexOAuth({
|
||||
prompter,
|
||||
runtime,
|
||||
isRemote: true,
|
||||
openUrl: async () => {},
|
||||
}),
|
||||
).rejects.toThrow("oauth failed");
|
||||
|
||||
expect(spin.stop).toHaveBeenCalledWith("OpenAI OAuth failed");
|
||||
expect(runtime.error).toHaveBeenCalledWith(expect.stringContaining("oauth failed"));
|
||||
expect(prompter.note).toHaveBeenCalledWith(
|
||||
"Trouble with OAuth? See https://docs.openclaw.ai/start/faq",
|
||||
"OAuth help",
|
||||
);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user