refactor(test): centralize auth test env lifecycle cleanup

This commit is contained in:
Peter Steinberger
2026-02-16 16:09:22 +00:00
parent 9a1e168685
commit 110b1cf46f
5 changed files with 48 additions and 49 deletions

View File

@@ -1,9 +1,8 @@
import fs from "node:fs/promises";
import { afterEach, describe, expect, it, vi } from "vitest"; import { afterEach, describe, expect, it, vi } from "vitest";
import type { WizardPrompter } from "../wizard/prompts.js"; import type { WizardPrompter } from "../wizard/prompts.js";
import { captureEnv } from "../test-utils/env.js";
import { applyAuthChoiceHuggingface } from "./auth-choice.apply.huggingface.js"; import { applyAuthChoiceHuggingface } from "./auth-choice.apply.huggingface.js";
import { import {
createAuthTestLifecycle,
createExitThrowingRuntime, createExitThrowingRuntime,
createWizardPrompter, createWizardPrompter,
readAuthProfilesForAgent, readAuthProfilesForAgent,
@@ -26,18 +25,17 @@ function createHuggingfacePrompter(params: {
} }
describe("applyAuthChoiceHuggingface", () => { describe("applyAuthChoiceHuggingface", () => {
const envSnapshot = captureEnv([ const lifecycle = createAuthTestLifecycle([
"OPENCLAW_STATE_DIR", "OPENCLAW_STATE_DIR",
"OPENCLAW_AGENT_DIR", "OPENCLAW_AGENT_DIR",
"PI_CODING_AGENT_DIR", "PI_CODING_AGENT_DIR",
"HF_TOKEN", "HF_TOKEN",
"HUGGINGFACE_HUB_TOKEN", "HUGGINGFACE_HUB_TOKEN",
]); ]);
let tempStateDir: string | null = null;
async function setupTempState() { async function setupTempState() {
const env = await setupAuthTestEnv("openclaw-hf-"); const env = await setupAuthTestEnv("openclaw-hf-");
tempStateDir = env.stateDir; lifecycle.setStateDir(env.stateDir);
return env.agentDir; return env.agentDir;
} }
@@ -48,11 +46,7 @@ describe("applyAuthChoiceHuggingface", () => {
} }
afterEach(async () => { afterEach(async () => {
if (tempStateDir) { await lifecycle.cleanup();
await fs.rm(tempStateDir, { recursive: true, force: true });
tempStateDir = null;
}
envSnapshot.restore();
}); });
it("returns null when authChoice is not huggingface-api-key", async () => { it("returns null when authChoice is not huggingface-api-key", async () => {

View File

@@ -2,7 +2,6 @@ import fs from "node:fs/promises";
import { afterEach, describe, expect, it, vi } from "vitest"; import { afterEach, describe, expect, it, vi } from "vitest";
import type { WizardPrompter } from "../wizard/prompts.js"; import type { WizardPrompter } from "../wizard/prompts.js";
import type { AuthChoice } from "./onboard-types.js"; import type { AuthChoice } from "./onboard-types.js";
import { captureEnv } from "../test-utils/env.js";
import { applyAuthChoice, resolvePreferredProviderForAuthChoice } from "./auth-choice.js"; import { applyAuthChoice, resolvePreferredProviderForAuthChoice } from "./auth-choice.js";
import { import {
MINIMAX_CN_API_BASE_URL, MINIMAX_CN_API_BASE_URL,
@@ -11,6 +10,7 @@ import {
} from "./onboard-auth.js"; } from "./onboard-auth.js";
import { import {
authProfilePathForAgent, authProfilePathForAgent,
createAuthTestLifecycle,
createExitThrowingRuntime, createExitThrowingRuntime,
createWizardPrompter, createWizardPrompter,
readAuthProfilesForAgent, readAuthProfilesForAgent,
@@ -43,7 +43,7 @@ type StoredAuthProfile = {
}; };
describe("applyAuthChoice", () => { describe("applyAuthChoice", () => {
const envSnapshot = captureEnv([ const lifecycle = createAuthTestLifecycle([
"OPENCLAW_STATE_DIR", "OPENCLAW_STATE_DIR",
"OPENCLAW_AGENT_DIR", "OPENCLAW_AGENT_DIR",
"PI_CODING_AGENT_DIR", "PI_CODING_AGENT_DIR",
@@ -57,10 +57,9 @@ describe("applyAuthChoice", () => {
"SSH_TTY", "SSH_TTY",
"CHUTES_CLIENT_ID", "CHUTES_CLIENT_ID",
]); ]);
let tempStateDir: string | null = null;
async function setupTempState() { async function setupTempState() {
const env = await setupAuthTestEnv("openclaw-auth-"); const env = await setupAuthTestEnv("openclaw-auth-");
tempStateDir = env.stateDir; lifecycle.setStateDir(env.stateDir);
} }
function createPrompter(overrides: Partial<WizardPrompter>): WizardPrompter { function createPrompter(overrides: Partial<WizardPrompter>): WizardPrompter {
return createWizardPrompter(overrides, { defaultSelect: "" }); return createWizardPrompter(overrides, { defaultSelect: "" });
@@ -102,11 +101,7 @@ describe("applyAuthChoice", () => {
resolvePluginProviders.mockReset(); resolvePluginProviders.mockReset();
loginOpenAICodexOAuth.mockReset(); loginOpenAICodexOAuth.mockReset();
loginOpenAICodexOAuth.mockResolvedValue(null); loginOpenAICodexOAuth.mockResolvedValue(null);
if (tempStateDir) { await lifecycle.cleanup();
await fs.rm(tempStateDir, { recursive: true, force: true });
tempStateDir = null;
}
envSnapshot.restore();
}); });
it("does not throw when openai-codex oauth fails", async () => { it("does not throw when openai-codex oauth fails", async () => {

View File

@@ -1,9 +1,8 @@
import fs from "node:fs/promises";
import { afterEach, describe, expect, it, vi } from "vitest"; import { afterEach, describe, expect, it, vi } from "vitest";
import type { WizardPrompter } from "../wizard/prompts.js"; import type { WizardPrompter } from "../wizard/prompts.js";
import { captureEnv } from "../test-utils/env.js";
import { applyAuthChoice } from "./auth-choice.js"; import { applyAuthChoice } from "./auth-choice.js";
import { import {
createAuthTestLifecycle,
createExitThrowingRuntime, createExitThrowingRuntime,
createWizardPrompter, createWizardPrompter,
readAuthProfilesForAgent, readAuthProfilesForAgent,
@@ -16,17 +15,16 @@ function createPrompter(overrides: Partial<WizardPrompter>): WizardPrompter {
} }
describe("applyAuthChoice (moonshot)", () => { describe("applyAuthChoice (moonshot)", () => {
const envSnapshot = captureEnv([ const lifecycle = createAuthTestLifecycle([
"OPENCLAW_STATE_DIR", "OPENCLAW_STATE_DIR",
"OPENCLAW_AGENT_DIR", "OPENCLAW_AGENT_DIR",
"PI_CODING_AGENT_DIR", "PI_CODING_AGENT_DIR",
"MOONSHOT_API_KEY", "MOONSHOT_API_KEY",
]); ]);
let tempStateDir: string | null = null;
async function setupTempState() { async function setupTempState() {
const env = await setupAuthTestEnv("openclaw-auth-"); const env = await setupAuthTestEnv("openclaw-auth-");
tempStateDir = env.stateDir; lifecycle.setStateDir(env.stateDir);
delete process.env.MOONSHOT_API_KEY; delete process.env.MOONSHOT_API_KEY;
} }
@@ -37,11 +35,7 @@ describe("applyAuthChoice (moonshot)", () => {
} }
afterEach(async () => { afterEach(async () => {
if (tempStateDir) { await lifecycle.cleanup();
await fs.rm(tempStateDir, { recursive: true, force: true });
tempStateDir = null;
}
envSnapshot.restore();
}); });
it("keeps the .cn baseUrl when setDefaultModel is false", async () => { it("keeps the .cn baseUrl when setDefaultModel is false", async () => {

View File

@@ -2,7 +2,6 @@ import type { OAuthCredentials } from "@mariozechner/pi-ai";
import fs from "node:fs/promises"; import fs from "node:fs/promises";
import path from "node:path"; import path from "node:path";
import { afterEach, describe, expect, it } from "vitest"; import { afterEach, describe, expect, it } from "vitest";
import { captureEnv } from "../test-utils/env.js";
import { import {
applyAuthProfileConfig, applyAuthProfileConfig,
applyLitellmProviderConfig, applyLitellmProviderConfig,
@@ -29,7 +28,11 @@ import {
ZAI_CODING_CN_BASE_URL, ZAI_CODING_CN_BASE_URL,
ZAI_GLOBAL_BASE_URL, ZAI_GLOBAL_BASE_URL,
} from "./onboard-auth.js"; } from "./onboard-auth.js";
import { readAuthProfilesForAgent, setupAuthTestEnv } from "./test-wizard-helpers.js"; import {
createAuthTestLifecycle,
readAuthProfilesForAgent,
setupAuthTestEnv,
} from "./test-wizard-helpers.js";
function createLegacyProviderConfig(params: { function createLegacyProviderConfig(params: {
providerId: string; providerId: string;
@@ -62,25 +65,20 @@ function createLegacyProviderConfig(params: {
} }
describe("writeOAuthCredentials", () => { describe("writeOAuthCredentials", () => {
const envSnapshot = captureEnv([ const lifecycle = createAuthTestLifecycle([
"OPENCLAW_STATE_DIR", "OPENCLAW_STATE_DIR",
"OPENCLAW_AGENT_DIR", "OPENCLAW_AGENT_DIR",
"PI_CODING_AGENT_DIR", "PI_CODING_AGENT_DIR",
"OPENCLAW_OAUTH_DIR", "OPENCLAW_OAUTH_DIR",
]); ]);
let tempStateDir: string | null = null;
afterEach(async () => { afterEach(async () => {
if (tempStateDir) { await lifecycle.cleanup();
await fs.rm(tempStateDir, { recursive: true, force: true });
tempStateDir = null;
}
envSnapshot.restore();
}); });
it("writes auth-profiles.json under OPENCLAW_AGENT_DIR when set", async () => { it("writes auth-profiles.json under OPENCLAW_AGENT_DIR when set", async () => {
const env = await setupAuthTestEnv("openclaw-oauth-"); const env = await setupAuthTestEnv("openclaw-oauth-");
tempStateDir = env.stateDir; lifecycle.setStateDir(env.stateDir);
const creds = { const creds = {
refresh: "refresh-token", refresh: "refresh-token",
@@ -100,30 +98,25 @@ describe("writeOAuthCredentials", () => {
}); });
await expect( await expect(
fs.readFile(path.join(tempStateDir, "agents", "main", "agent", "auth-profiles.json"), "utf8"), fs.readFile(path.join(env.stateDir, "agents", "main", "agent", "auth-profiles.json"), "utf8"),
).rejects.toThrow(); ).rejects.toThrow();
}); });
}); });
describe("setMinimaxApiKey", () => { describe("setMinimaxApiKey", () => {
const envSnapshot = captureEnv([ const lifecycle = createAuthTestLifecycle([
"OPENCLAW_STATE_DIR", "OPENCLAW_STATE_DIR",
"OPENCLAW_AGENT_DIR", "OPENCLAW_AGENT_DIR",
"PI_CODING_AGENT_DIR", "PI_CODING_AGENT_DIR",
]); ]);
let tempStateDir: string | null = null;
afterEach(async () => { afterEach(async () => {
if (tempStateDir) { await lifecycle.cleanup();
await fs.rm(tempStateDir, { recursive: true, force: true });
tempStateDir = null;
}
envSnapshot.restore();
}); });
it("writes to OPENCLAW_AGENT_DIR when set", async () => { it("writes to OPENCLAW_AGENT_DIR when set", async () => {
const env = await setupAuthTestEnv("openclaw-minimax-", { agentSubdir: "custom-agent" }); const env = await setupAuthTestEnv("openclaw-minimax-", { agentSubdir: "custom-agent" });
tempStateDir = env.stateDir; lifecycle.setStateDir(env.stateDir);
await setMinimaxApiKey("sk-minimax-test"); await setMinimaxApiKey("sk-minimax-test");
@@ -137,7 +130,7 @@ describe("setMinimaxApiKey", () => {
}); });
await expect( await expect(
fs.readFile(path.join(tempStateDir, "agents", "main", "agent", "auth-profiles.json"), "utf8"), fs.readFile(path.join(env.stateDir, "agents", "main", "agent", "auth-profiles.json"), "utf8"),
).rejects.toThrow(); ).rejects.toThrow();
}); });
}); });

View File

@@ -4,6 +4,7 @@ import { vi } from "vitest";
import type { RuntimeEnv } from "../runtime.js"; import type { RuntimeEnv } from "../runtime.js";
import type { WizardPrompter } from "../wizard/prompts.js"; import type { WizardPrompter } from "../wizard/prompts.js";
import { makeTempWorkspace } from "../test-helpers/workspace.js"; import { makeTempWorkspace } from "../test-helpers/workspace.js";
import { captureEnv } from "../test-utils/env.js";
export const noopAsync = async () => {}; export const noopAsync = async () => {};
export const noop = () => {}; export const noop = () => {};
@@ -51,6 +52,28 @@ export async function setupAuthTestEnv(
return { stateDir, agentDir }; return { stateDir, agentDir };
} }
export type AuthTestLifecycle = {
setStateDir: (stateDir: string) => void;
cleanup: () => Promise<void>;
};
export function createAuthTestLifecycle(envKeys: string[]): AuthTestLifecycle {
const envSnapshot = captureEnv(envKeys);
let stateDir: string | null = null;
return {
setStateDir(nextStateDir: string) {
stateDir = nextStateDir;
},
async cleanup() {
if (stateDir) {
await fs.rm(stateDir, { recursive: true, force: true });
stateDir = null;
}
envSnapshot.restore();
},
};
}
export function requireOpenClawAgentDir(): string { export function requireOpenClawAgentDir(): string {
const agentDir = process.env.OPENCLAW_AGENT_DIR; const agentDir = process.env.OPENCLAW_AGENT_DIR;
if (!agentDir) { if (!agentDir) {