test: share google oauth fetch fixture

This commit is contained in:
Peter Steinberger
2026-04-20 21:33:37 +01:00
parent 3a8aed4c77
commit fa7da15be1

View File

@@ -583,6 +583,48 @@ describe("loginGeminiCliOAuth", () => {
});
}
function tokenResponse(): Response {
return responseJson({
access_token: "access-token",
refresh_token: "refresh-token",
expires_in: 3600,
});
}
function userInfoResponse(): Response {
return responseJson({ email: "lobster@openclaw.ai" });
}
type RecordedFetchRequest = {
url: string;
init?: RequestInit;
};
function installGeminiOAuthFetchMock(
handleRequest: (request: RecordedFetchRequest) => Response | undefined,
) {
const requests: RecordedFetchRequest[] = [];
const fetchMock = vi.fn(async (input: string | URL | Request, init?: RequestInit) => {
const request = { url: getRequestUrl(input), init };
requests.push(request);
if (request.url === TOKEN_URL) {
return tokenResponse();
}
if (request.url === USERINFO_URL) {
return userInfoResponse();
}
const response = handleRequest(request);
if (response) {
return response;
}
throw new Error(`Unexpected request: ${request.url}`);
});
vi.stubGlobal("fetch", fetchMock);
return { fetchMock, requests };
}
function getFormField(body: RequestInit["body"], name: string): string | null {
if (!(body instanceof URLSearchParams)) {
throw new Error("Expected URLSearchParams body");
@@ -675,21 +717,7 @@ describe("loginGeminiCliOAuth", () => {
});
it("falls back across loadCodeAssist endpoints with aligned headers and metadata", async () => {
const requests: Array<{ url: string; init?: RequestInit }> = [];
const fetchMock = vi.fn(async (input: string | URL | Request, init?: RequestInit) => {
const url = getRequestUrl(input);
requests.push({ url, init });
if (url === TOKEN_URL) {
return responseJson({
access_token: "access-token",
refresh_token: "refresh-token",
expires_in: 3600,
});
}
if (url === USERINFO_URL) {
return responseJson({ email: "lobster@openclaw.ai" });
}
const { requests } = installGeminiOAuthFetchMock(({ url }) => {
if (url === LOAD_PROD) {
return responseJson({ error: { message: "temporary failure" } }, 503);
}
@@ -699,9 +727,8 @@ describe("loginGeminiCliOAuth", () => {
cloudaicompanionProject: { id: "daily-project" },
});
}
throw new Error(`Unexpected request: ${url}`);
return undefined;
});
vi.stubGlobal("fetch", fetchMock);
const { loginGeminiCliOAuth } = await import("./oauth.js");
await runRemoteLoginExpectingProjectId(loginGeminiCliOAuth, "daily-project");
@@ -729,30 +756,15 @@ describe("loginGeminiCliOAuth", () => {
});
it("keeps OAuth state separate from the PKCE verifier during manual login", async () => {
const requests: Array<{ url: string; init?: RequestInit }> = [];
const fetchMock = vi.fn(async (input: string | URL | Request, init?: RequestInit) => {
const url = getRequestUrl(input);
requests.push({ url, init });
if (url === TOKEN_URL) {
return responseJson({
access_token: "access-token",
refresh_token: "refresh-token",
expires_in: 3600,
});
}
if (url === USERINFO_URL) {
return responseJson({ email: "lobster@openclaw.ai" });
}
const { requests } = installGeminiOAuthFetchMock(({ url }) => {
if (url === LOAD_PROD) {
return responseJson({
currentTier: { id: "standard-tier" },
cloudaicompanionProject: { id: "prod-project" },
});
}
throw new Error(`Unexpected request: ${url}`);
return undefined;
});
vi.stubGlobal("fetch", fetchMock);
const { loginGeminiCliOAuth } = await import("./oauth.js");
const { authUrl } = await runRemoteLoginWithCapturedAuthUrl(loginGeminiCliOAuth);
@@ -786,32 +798,17 @@ describe("loginGeminiCliOAuth", () => {
it("falls back to GOOGLE_CLOUD_PROJECT when all loadCodeAssist endpoints fail", async () => {
process.env.GOOGLE_CLOUD_PROJECT = "env-project";
const requests: string[] = [];
const fetchMock = vi.fn(async (input: string | URL | Request) => {
const url = getRequestUrl(input);
requests.push(url);
if (url === TOKEN_URL) {
return responseJson({
access_token: "access-token",
refresh_token: "refresh-token",
expires_in: 3600,
});
}
if (url === USERINFO_URL) {
return responseJson({ email: "lobster@openclaw.ai" });
}
const { requests } = installGeminiOAuthFetchMock(({ url }) => {
if ([LOAD_PROD, LOAD_DAILY, LOAD_AUTOPUSH].includes(url)) {
return responseJson({ error: { message: "unavailable" } }, 503);
}
throw new Error(`Unexpected request: ${url}`);
return undefined;
});
vi.stubGlobal("fetch", fetchMock);
const { loginGeminiCliOAuth } = await import("./oauth.js");
await runRemoteLoginExpectingProjectId(loginGeminiCliOAuth, "env-project");
expect(requests.filter((url) => url.includes("v1internal:loadCodeAssist"))).toHaveLength(3);
expect(requests.some((url) => url.includes("v1internal:onboardUser"))).toBe(false);
expect(requests.filter(({ url }) => url.includes("v1internal:loadCodeAssist"))).toHaveLength(3);
expect(requests.some(({ url }) => url.includes("v1internal:onboardUser"))).toBe(false);
});
it("skips loadCodeAssist entirely when Gemini CLI is configured for personal OAuth", async () => {
@@ -826,29 +823,12 @@ describe("loginGeminiCliOAuth", () => {
}),
);
const requests: string[] = [];
const fetchMock = vi.fn(async (input: string | URL | Request) => {
const url = getRequestUrl(input);
requests.push(url);
if (url === TOKEN_URL) {
return responseJson({
access_token: "access-token",
refresh_token: "refresh-token",
expires_in: 3600,
});
}
if (url === USERINFO_URL) {
return responseJson({ email: "lobster@openclaw.ai" });
}
throw new Error(`Unexpected request: ${url}`);
});
vi.stubGlobal("fetch", fetchMock);
const { requests } = installGeminiOAuthFetchMock(() => undefined);
const { loginGeminiCliOAuth } = await import("./oauth.js");
const { result } = await runRemoteLoginWithCapturedAuthUrl(loginGeminiCliOAuth);
expect(result.projectId).toBeUndefined();
expect(requests).toEqual([TOKEN_URL, USERINFO_URL]);
expect(requests.map(({ url }) => url)).toEqual([TOKEN_URL, USERINFO_URL]);
});
});