


























@@ -81,6 +81,30 @@ vi.mock("../secrets/provider-env-vars.js", () => ({
8181getProviderEnvVars: vi.fn((provider: string) => providerEnvVarsById[provider] ?? []),
8282}));
838384+function requireRecord(value: unknown, label: string): Record<string, unknown> {
85+expect(typeof value, label).toBe("object");
86+expect(value, label).not.toBeNull();
87+return value as Record<string, unknown>;
88+}
89+90+function expectFields(value: unknown, expected: Record<string, unknown>, label = "record") {
91+const record = requireRecord(value, label);
92+for (const [key, expectedValue] of Object.entries(expected)) {
93+expect(record[key], key).toEqual(expectedValue);
94+}
95+return record;
96+}
97+98+async function expectMissingFile(readPromise: Promise<unknown>) {
99+try {
100+await readPromise;
101+} catch (error) {
102+expectFields(error, { code: "ENOENT" }, "read error");
103+return;
104+}
105+throw new Error("Expected file read to fail with ENOENT");
106+}
107+84108describe("writeOAuthCredentials", () => {
85109const lifecycle = createAuthTestLifecycle([
86110"OPENCLAW_STATE_DIR",
@@ -112,15 +136,13 @@ describe("writeOAuthCredentials", () => {
112136const parsed = await readAuthProfilesForAgent<{
113137profiles?: Record<string, OAuthCredentials & { type?: string }>;
114138}>(defaultAgentDir);
115-expect(parsed.profiles?.["openai-codex:default"]).toMatchObject({
139+expectFields(parsed.profiles?.["openai-codex:default"], {
116140refresh: "refresh-token",
117141access: "access-token",
118142type: "oauth",
119143});
120144121-await expect(
122-fs.readFile(path.join(env.agentDir, "auth-profiles.json"), "utf8"),
123-).rejects.toMatchObject({ code: "ENOENT" });
145+await expectMissingFile(fs.readFile(path.join(env.agentDir, "auth-profiles.json"), "utf8"));
124146});
125147126148it("writes OAuth credentials to all sibling agent dirs when syncSiblingAgents=true", async () => {
@@ -152,7 +174,7 @@ describe("writeOAuthCredentials", () => {
152174const parsed = JSON.parse(raw) as {
153175profiles?: Record<string, OAuthCredentials & { type?: string }>;
154176};
155-expect(parsed.profiles?.["openai-codex:default"]).toMatchObject({
177+expectFields(parsed.profiles?.["openai-codex:default"], {
156178refresh: "refresh-sync",
157179access: "access-sync",
158180type: "oauth",
@@ -184,14 +206,12 @@ describe("writeOAuthCredentials", () => {
184206const kidParsed = JSON.parse(kidRaw) as {
185207profiles?: Record<string, OAuthCredentials & { type?: string }>;
186208};
187-expect(kidParsed.profiles?.["openai-codex:default"]).toMatchObject({
209+expectFields(kidParsed.profiles?.["openai-codex:default"], {
188210access: "access-kid",
189211type: "oauth",
190212});
191213192-await expect(fs.readFile(authProfilePathFor(mainAgentDir), "utf8")).rejects.toMatchObject({
193-code: "ENOENT",
194-});
214+await expectMissingFile(fs.readFile(authProfilePathFor(mainAgentDir), "utf8"));
195215});
196216197217it("syncs siblings from explicit agentDir outside OPENCLAW_STATE_DIR", async () => {
@@ -223,7 +243,7 @@ describe("writeOAuthCredentials", () => {
223243const parsed = JSON.parse(raw) as {
224244profiles?: Record<string, OAuthCredentials & { type?: string }>;
225245};
226-expect(parsed.profiles?.["openai-codex:default"]).toMatchObject({
246+expectFields(parsed.profiles?.["openai-codex:default"], {
227247refresh: "refresh-ext",
228248access: "access-ext",
229249type: "oauth",
@@ -232,9 +252,7 @@ describe("writeOAuthCredentials", () => {
232252233253// Global state dir should NOT have credentials written
234254const globalMain = path.join(tempStateDir, "agents", "main", "agent");
235-await expect(fs.readFile(authProfilePathFor(globalMain), "utf8")).rejects.toMatchObject({
236-code: "ENOENT",
237-});
255+await expectMissingFile(fs.readFile(authProfilePathFor(globalMain), "utf8"));
238256});
239257});
240258@@ -280,11 +298,11 @@ describe("upsertApiKeyProfile secret refs", () => {
280298});
281299upsertApiKeyProfile({ provider: "openai", input: "sk-openai-env", agentDir: env.agentDir });
282300283-expect(await readProfile(env.agentDir, "moonshot:default")).toMatchObject({
301+expectFields(await readProfile(env.agentDir, "moonshot:default"), {
284302key: "sk-moonshot-env",
285303});
286304expect((await readProfile(env.agentDir, "moonshot:default"))?.keyRef).toBeUndefined();
287-expect(await readProfile(env.agentDir, "openai:default")).toMatchObject({
305+expectFields(await readProfile(env.agentDir, "openai:default"), {
288306key: "sk-openai-env",
289307});
290308expect((await readProfile(env.agentDir, "openai:default"))?.keyRef).toBeUndefined();
@@ -315,18 +333,18 @@ describe("upsertApiKeyProfile secret refs", () => {
315333profileId: "moonshot:plain",
316334});
317335318-expect(await readProfile(env.agentDir, "moonshot:default")).toMatchObject({
336+expectFields(await readProfile(env.agentDir, "moonshot:default"), {
319337keyRef: { source: "env", provider: "default", id: "MOONSHOT_API_KEY" },
320338});
321339expect((await readProfile(env.agentDir, "moonshot:default"))?.key).toBeUndefined();
322-expect(await readProfile(env.agentDir, "openai:default")).toMatchObject({
340+expectFields(await readProfile(env.agentDir, "openai:default"), {
323341keyRef: { source: "env", provider: "default", id: "OPENAI_API_KEY" },
324342});
325343expect((await readProfile(env.agentDir, "openai:default"))?.key).toBeUndefined();
326-expect(await readProfile(env.agentDir, "moonshot:inline")).toMatchObject({
344+expectFields(await readProfile(env.agentDir, "moonshot:inline"), {
327345keyRef: { source: "env", provider: "default", id: "MOONSHOT_API_KEY" },
328346});
329-expect(await readProfile(env.agentDir, "moonshot:plain")).toMatchObject({
347+expectFields(await readProfile(env.agentDir, "moonshot:plain"), {
330348key: "sk-moonshot-plaintext",
331349});
332350expect((await readProfile(env.agentDir, "moonshot:plain"))?.keyRef).toBeUndefined();
@@ -364,21 +382,21 @@ describe("upsertApiKeyProfile secret refs", () => {
364382});
365383}
366384367-expect(await readProfile(env.agentDir, "cloudflare-ai-gateway:default")).toMatchObject({
385+expectFields(await readProfile(env.agentDir, "cloudflare-ai-gateway:default"), {
368386keyRef: { source: "env", provider: "default", id: "CLOUDFLARE_AI_GATEWAY_API_KEY" },
369387metadata: { accountId: "account-1", gatewayId: "gateway-1" },
370388});
371389expect((await readProfile(env.agentDir, "cloudflare-ai-gateway:default"))?.key).toBeUndefined();
372-expect(await readProfile(env.agentDir, "volcengine:default")).toMatchObject({
390+expectFields(await readProfile(env.agentDir, "volcengine:default"), {
373391keyRef: { source: "env", provider: "default", id: "VOLCANO_ENGINE_API_KEY" },
374392});
375-expect(await readProfile(env.agentDir, "byteplus:default")).toMatchObject({
393+expectFields(await readProfile(env.agentDir, "byteplus:default"), {
376394keyRef: { source: "env", provider: "default", id: "BYTEPLUS_API_KEY" },
377395});
378-expect(await readProfile(env.agentDir, "opencode:default")).toMatchObject({
396+expectFields(await readProfile(env.agentDir, "opencode:default"), {
379397keyRef: { source: "env", provider: "default", id: "OPENCODE_API_KEY" },
380398});
381-expect(await readProfile(env.agentDir, "opencode-go:default")).toMatchObject({
399+expectFields(await readProfile(env.agentDir, "opencode-go:default"), {
382400keyRef: { source: "env", provider: "default", id: "OPENCODE_API_KEY" },
383401});
384402});
@@ -405,15 +423,13 @@ describe("upsertApiKeyProfile", () => {
405423const parsed = await readAuthProfilesForAgent<{
406424profiles?: Record<string, { type?: string; provider?: string; key?: string }>;
407425}>(defaultAgentDir);
408-expect(parsed.profiles?.["minimax:default"]).toMatchObject({
426+expectFields(parsed.profiles?.["minimax:default"], {
409427type: "api_key",
410428provider: "minimax",
411429key: "sk-minimax-test",
412430});
413431414-await expect(
415-fs.readFile(path.join(env.agentDir, "auth-profiles.json"), "utf8"),
416-).rejects.toMatchObject({ code: "ENOENT" });
432+await expectMissingFile(fs.readFile(path.join(env.agentDir, "auth-profiles.json"), "utf8"));
417433});
418434});
419435此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。