| import { beforeEach, describe, expect, it, vi } from "vitest"; |
| import type { OpenClawConfig } from "../../config/config.js"; |
|
|
| const mocks = vi.hoisted(() => ({ |
| readConfigFileSnapshot: vi.fn(), |
| writeConfigFile: vi.fn(), |
| })); |
|
|
| vi.mock("../../config/config.js", () => ({ |
| readConfigFileSnapshot: (...args: unknown[]) => mocks.readConfigFileSnapshot(...args), |
| writeConfigFile: (...args: unknown[]) => mocks.writeConfigFile(...args), |
| })); |
|
|
| import { loadValidConfigOrThrow, updateConfig } from "./shared.js"; |
|
|
| describe("models/shared", () => { |
| beforeEach(() => { |
| mocks.readConfigFileSnapshot.mockClear(); |
| mocks.writeConfigFile.mockClear(); |
| }); |
|
|
| it("returns config when snapshot is valid", async () => { |
| const cfg = { providers: {} } as unknown as OpenClawConfig; |
| mocks.readConfigFileSnapshot.mockResolvedValue({ |
| valid: true, |
| config: cfg, |
| }); |
|
|
| await expect(loadValidConfigOrThrow()).resolves.toBe(cfg); |
| }); |
|
|
| it("throws formatted issues when snapshot is invalid", async () => { |
| mocks.readConfigFileSnapshot.mockResolvedValue({ |
| valid: false, |
| path: "/tmp/openclaw.json", |
| issues: [{ path: "providers.openai.apiKey", message: "Required" }], |
| }); |
|
|
| await expect(loadValidConfigOrThrow()).rejects.toThrowError( |
| "Invalid config at /tmp/openclaw.json\n- providers.openai.apiKey: Required", |
| ); |
| }); |
|
|
| it("updateConfig writes mutated config", async () => { |
| const cfg = { update: { channel: "stable" } } as unknown as OpenClawConfig; |
| mocks.readConfigFileSnapshot.mockResolvedValue({ |
| valid: true, |
| config: cfg, |
| }); |
| mocks.writeConfigFile.mockResolvedValue(undefined); |
|
|
| await updateConfig((current) => ({ |
| ...current, |
| update: { channel: "beta" }, |
| })); |
|
|
| expect(mocks.writeConfigFile).toHaveBeenCalledWith( |
| expect.objectContaining({ |
| update: { channel: "beta" }, |
| }), |
| ); |
| }); |
| }); |
|
|