import type { ChannelAccountSnapshot, ChannelGatewayContext } from "openclaw/plugin-sdk/test-utils"; import { expect, vi } from "vitest"; import { createStartAccountContext } from "./start-account-context.js"; export function startAccountAndTrackLifecycle(params: { startAccount: (ctx: ChannelGatewayContext) => Promise; account: TAccount; }) { const patches: ChannelAccountSnapshot[] = []; const abort = new AbortController(); const task = params.startAccount( createStartAccountContext({ account: params.account, abortSignal: abort.signal, statusPatchSink: (next) => patches.push({ ...next }), }), ); let settled = false; void task.then(() => { settled = true; }); return { abort, patches, task, isSettled: () => settled, }; } export async function abortStartedAccount(params: { abort: AbortController; task: Promise; }) { params.abort.abort(); await params.task; } export async function expectPendingUntilAbort(params: { waitForStarted: () => Promise; isSettled: () => boolean; abort: AbortController; task: Promise; assertBeforeAbort?: () => void; assertAfterAbort?: () => void; }) { await params.waitForStarted(); expect(params.isSettled()).toBe(false); params.assertBeforeAbort?.(); await abortStartedAccount({ abort: params.abort, task: params.task }); params.assertAfterAbort?.(); } export async function expectStopPendingUntilAbort(params: { waitForStarted: () => Promise; isSettled: () => boolean; abort: AbortController; task: Promise; stop: ReturnType; }) { await expectPendingUntilAbort({ waitForStarted: params.waitForStarted, isSettled: params.isSettled, abort: params.abort, task: params.task, assertBeforeAbort: () => { expect(params.stop).not.toHaveBeenCalled(); }, assertAfterAbort: () => { expect(params.stop).toHaveBeenCalledOnce(); }, }); }