diff --git a/extensions/line/src/channel.logout.test.ts b/extensions/line/src/channel.logout.test.ts index dbceacee7d9..c2864ec70c0 100644 --- a/extensions/line/src/channel.logout.test.ts +++ b/extensions/line/src/channel.logout.test.ts @@ -47,15 +47,50 @@ function createRuntime(): { runtime: PluginRuntime; mocks: LineRuntimeMocks } { return { runtime, mocks: { writeConfigFile, resolveLineAccount } }; } +function createRuntimeEnv(): RuntimeEnv { + return { + log: vi.fn(), + error: vi.fn(), + exit: vi.fn((code: number): never => { + throw new Error(`exit ${code}`); + }), + }; +} + +function resolveAccount( + resolveLineAccount: LineRuntimeMocks["resolveLineAccount"], + cfg: OpenClawConfig, + accountId: string, +): ResolvedLineAccount { + const resolver = resolveLineAccount as unknown as (params: { + cfg: OpenClawConfig; + accountId?: string; + }) => ResolvedLineAccount; + return resolver({ cfg, accountId }); +} + +async function runLogoutScenario(params: { cfg: OpenClawConfig; accountId: string }): Promise<{ + result: Awaited["logoutAccount"]>>>; + mocks: LineRuntimeMocks; +}> { + const { runtime, mocks } = createRuntime(); + setLineRuntime(runtime); + const account = resolveAccount(mocks.resolveLineAccount, params.cfg, params.accountId); + const result = await linePlugin.gateway!.logoutAccount!({ + accountId: params.accountId, + cfg: params.cfg, + account, + runtime: createRuntimeEnv(), + }); + return { result, mocks }; +} + describe("linePlugin gateway.logoutAccount", () => { beforeEach(() => { setLineRuntime(createRuntime().runtime); }); it("clears tokenFile/secretFile on default account logout", async () => { - const { runtime, mocks } = createRuntime(); - setLineRuntime(runtime); - const cfg: OpenClawConfig = { channels: { line: { @@ -64,38 +99,17 @@ describe("linePlugin gateway.logoutAccount", () => { }, }, }; - const runtimeEnv: RuntimeEnv = { - log: vi.fn(), - error: vi.fn(), - exit: vi.fn((code: number): never => { - throw new Error(`exit ${code}`); - }), - }; - const resolveAccount = mocks.resolveLineAccount as unknown as (params: { - cfg: OpenClawConfig; - accountId?: string; - }) => ResolvedLineAccount; - const account = resolveAccount({ + const { result, mocks } = await runLogoutScenario({ cfg, accountId: DEFAULT_ACCOUNT_ID, }); - const result = await linePlugin.gateway!.logoutAccount!({ - accountId: DEFAULT_ACCOUNT_ID, - cfg, - account, - runtime: runtimeEnv, - }); - expect(result.cleared).toBe(true); expect(result.loggedOut).toBe(true); expect(mocks.writeConfigFile).toHaveBeenCalledWith({}); }); it("clears tokenFile/secretFile on account logout", async () => { - const { runtime, mocks } = createRuntime(); - setLineRuntime(runtime); - const cfg: OpenClawConfig = { channels: { line: { @@ -108,31 +122,35 @@ describe("linePlugin gateway.logoutAccount", () => { }, }, }; - const runtimeEnv: RuntimeEnv = { - log: vi.fn(), - error: vi.fn(), - exit: vi.fn((code: number): never => { - throw new Error(`exit ${code}`); - }), - }; - const resolveAccount = mocks.resolveLineAccount as unknown as (params: { - cfg: OpenClawConfig; - accountId?: string; - }) => ResolvedLineAccount; - const account = resolveAccount({ + const { result, mocks } = await runLogoutScenario({ cfg, accountId: "primary", }); - const result = await linePlugin.gateway!.logoutAccount!({ - accountId: "primary", - cfg, - account, - runtime: runtimeEnv, - }); - expect(result.cleared).toBe(true); expect(result.loggedOut).toBe(true); expect(mocks.writeConfigFile).toHaveBeenCalledWith({}); }); + + it("does not write config when account has no token/secret fields", async () => { + const cfg: OpenClawConfig = { + channels: { + line: { + accounts: { + primary: { + name: "Primary", + }, + }, + }, + }, + }; + const { result, mocks } = await runLogoutScenario({ + cfg, + accountId: "primary", + }); + + expect(result.cleared).toBe(false); + expect(result.loggedOut).toBe(true); + expect(mocks.writeConfigFile).not.toHaveBeenCalled(); + }); });