Skip to content

Commit 253982d

Browse files
committed
test: keep command setup hook tests narrow
1 parent be9bef3 commit 253982d

3 files changed

Lines changed: 68 additions & 131 deletions

File tree

src/commands/onboard-channels.post-write.test.ts

Lines changed: 33 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -1,137 +1,52 @@
1-
import { beforeEach, describe, expect, it, vi } from "vitest";
1+
import { describe, expect, it, vi } from "vitest";
22
import type { OpenClawConfig } from "../config/config.js";
3-
import { setActivePluginRegistry } from "../plugins/runtime.js";
4-
import { createChannelTestPluginBase, createTestRegistry } from "../test-utils/channel-plugins.js";
5-
import type { WizardPrompter } from "../wizard/prompts.js";
6-
import { patchChannelSetupWizardAdapter } from "./channel-test-helpers.js";
73
import {
4+
createChannelOnboardingPostWriteHook,
85
createChannelOnboardingPostWriteHookCollector,
96
runCollectedChannelOnboardingPostWriteHooks,
10-
setupChannels,
117
} from "./onboard-channels.js";
12-
import { createExitThrowingRuntime, createWizardPrompter } from "./test-wizard-helpers.js";
13-
14-
function setMinimalTelegramOnboardingRegistryForTests(): void {
15-
setActivePluginRegistry(
16-
createTestRegistry([
17-
{
18-
pluginId: "telegram",
19-
source: "test",
20-
plugin: {
21-
...createChannelTestPluginBase({
22-
id: "telegram",
23-
label: "Telegram",
24-
capabilities: { chatTypes: ["direct", "group"] },
25-
}),
26-
setup: {
27-
applyAccountConfig: ({ cfg }: { cfg: OpenClawConfig }) => cfg,
28-
},
29-
setupWizard: {
30-
channel: "telegram",
31-
status: {
32-
configuredLabel: "Configured",
33-
unconfiguredLabel: "Not configured",
34-
resolveConfigured: ({ cfg }: { cfg: OpenClawConfig }) =>
35-
Boolean(cfg.channels?.telegram?.botToken),
36-
},
37-
credentials: [],
38-
},
39-
},
40-
},
41-
]),
42-
);
43-
}
44-
45-
function createPrompter(overrides: Partial<WizardPrompter>): WizardPrompter {
46-
return createWizardPrompter(
47-
{
48-
progress: vi.fn(() => ({ update: vi.fn(), stop: vi.fn() })),
49-
...overrides,
50-
},
51-
{ defaultSelect: "__done__" },
52-
);
53-
}
54-
55-
function createQuickstartTelegramSelect() {
56-
return vi.fn(async ({ message }: { message: string }) => {
57-
if (message === "Select channel (QuickStart)") {
58-
return "telegram";
59-
}
60-
return "__done__";
61-
});
62-
}
63-
64-
function createUnexpectedQuickstartPrompter(select: WizardPrompter["select"]) {
65-
return createPrompter({
66-
select,
67-
multiselect: vi.fn(async () => {
68-
throw new Error("unexpected multiselect");
69-
}),
70-
text: vi.fn(async ({ message }: { message: string }) => {
71-
throw new Error(`unexpected text prompt: ${message}`);
72-
}) as unknown as WizardPrompter["text"],
73-
});
74-
}
8+
import { createExitThrowingRuntime } from "./test-wizard-helpers.js";
759

7610
describe("setupChannels post-write hooks", () => {
77-
beforeEach(() => {
78-
setMinimalTelegramOnboardingRegistryForTests();
79-
});
80-
8111
it("collects onboarding post-write hooks and runs them against the final config", async () => {
82-
const select = createQuickstartTelegramSelect();
8312
const afterConfigWritten = vi.fn(async () => {});
84-
const configureInteractive = vi.fn(async ({ cfg }: { cfg: OpenClawConfig }) => ({
85-
cfg: {
86-
...cfg,
87-
channels: {
88-
...cfg.channels,
89-
telegram: { ...cfg.channels?.telegram, botToken: "new-token" },
90-
},
91-
} as OpenClawConfig,
92-
accountId: "acct-1",
93-
}));
94-
const restore = patchChannelSetupWizardAdapter("telegram", {
95-
configureInteractive,
13+
const previousCfg = {} as OpenClawConfig;
14+
const cfg = {
15+
channels: {
16+
telegram: { botToken: "new-token" },
17+
},
18+
} as OpenClawConfig;
19+
const adapter = {
9620
afterConfigWritten,
97-
getStatus: vi.fn(async ({ cfg }: { cfg: OpenClawConfig }) => ({
98-
channel: "telegram",
99-
configured: Boolean(cfg.channels?.telegram?.botToken),
100-
statusLines: [],
101-
})),
102-
});
103-
const prompter = createUnexpectedQuickstartPrompter(
104-
select as unknown as WizardPrompter["select"],
105-
);
21+
};
10622
const collector = createChannelOnboardingPostWriteHookCollector();
10723
const runtime = createExitThrowingRuntime();
24+
const hook = createChannelOnboardingPostWriteHook({
25+
accountId: "acct-1",
26+
adapter,
27+
channel: "telegram",
28+
previousCfg,
29+
});
10830

109-
try {
110-
const cfg = await setupChannels({} as OpenClawConfig, runtime, prompter, {
111-
quickstartDefaults: true,
112-
skipConfirm: true,
113-
onPostWriteHook: (hook) => {
114-
collector.collect(hook);
115-
},
116-
});
31+
if (!hook) {
32+
throw new Error("expected post-write hook");
33+
}
34+
collector.collect(hook);
11735

118-
expect(afterConfigWritten).not.toHaveBeenCalled();
36+
expect(afterConfigWritten).not.toHaveBeenCalled();
11937

120-
await runCollectedChannelOnboardingPostWriteHooks({
121-
hooks: collector.drain(),
122-
cfg,
123-
runtime,
124-
});
38+
await runCollectedChannelOnboardingPostWriteHooks({
39+
hooks: collector.drain(),
40+
cfg,
41+
runtime,
42+
});
12543

126-
expect(afterConfigWritten).toHaveBeenCalledWith({
127-
previousCfg: {} as OpenClawConfig,
128-
cfg,
129-
accountId: "acct-1",
130-
runtime,
131-
});
132-
} finally {
133-
restore();
134-
}
44+
expect(afterConfigWritten).toHaveBeenCalledWith({
45+
previousCfg,
46+
cfg,
47+
accountId: "acct-1",
48+
runtime,
49+
});
13550
});
13651

13752
it("logs onboarding post-write hook failures without aborting", async () => {

src/commands/onboard-channels.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export {
2+
createChannelOnboardingPostWriteHook,
23
createChannelOnboardingPostWriteHookCollector,
34
noteChannelStatus,
45
runCollectedChannelOnboardingPostWriteHooks,

src/flows/channel-setup.ts

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ import {
44
getChannelSetupPlugin,
55
listChannelSetupPlugins,
66
} from "../channels/plugins/setup-registry.js";
7-
import type { ChannelSetupPlugin } from "../channels/plugins/setup-wizard-types.js";
7+
import type {
8+
ChannelSetupPlugin,
9+
ChannelSetupWizardAdapter,
10+
} from "../channels/plugins/setup-wizard-types.js";
811
import { listChatChannels } from "../channels/registry.js";
912
import { formatCliCommand } from "../cli/command-format.js";
1013
import {
@@ -77,6 +80,28 @@ export async function runCollectedChannelOnboardingPostWriteHooks(params: {
7780
}
7881
}
7982

83+
export function createChannelOnboardingPostWriteHook(params: {
84+
accountId?: string;
85+
adapter?: Pick<ChannelSetupWizardAdapter, "afterConfigWritten">;
86+
channel: ChannelChoice;
87+
previousCfg: OpenClawConfig;
88+
}): ChannelOnboardingPostWriteHook | undefined {
89+
if (!params.accountId || !params.adapter?.afterConfigWritten) {
90+
return undefined;
91+
}
92+
return {
93+
channel: params.channel,
94+
accountId: params.accountId,
95+
run: async ({ cfg, runtime }) =>
96+
await params.adapter?.afterConfigWritten?.({
97+
previousCfg: params.previousCfg,
98+
cfg,
99+
accountId: params.accountId!,
100+
runtime,
101+
}),
102+
};
103+
}
104+
80105
// Channel-specific prompts moved into setup flow adapters.
81106

82107
export async function setupChannels(
@@ -336,18 +361,14 @@ export async function setupChannels(
336361
const adapter = getVisibleSetupFlowAdapter(channel);
337362
if (result.accountId) {
338363
recordAccount(channel, result.accountId);
339-
if (adapter?.afterConfigWritten) {
340-
options?.onPostWriteHook?.({
341-
channel,
342-
accountId: result.accountId,
343-
run: async ({ cfg, runtime }) =>
344-
await adapter.afterConfigWritten?.({
345-
previousCfg,
346-
cfg,
347-
accountId: result.accountId!,
348-
runtime,
349-
}),
350-
});
364+
const postWriteHook = createChannelOnboardingPostWriteHook({
365+
accountId: result.accountId,
366+
adapter,
367+
channel,
368+
previousCfg,
369+
});
370+
if (postWriteHook) {
371+
options?.onPostWriteHook?.(postWriteHook);
351372
}
352373
}
353374
addSelection(channel);

0 commit comments

Comments
 (0)