import type { ChannelSetupWizardAdapter } from
"openclaw/plugin-sdk/setup" ;
import { describe, expect, it, vi } from
"vitest" ;
import { createMatrixSetupWizardProxy, matrixSetupAdapter } from
"./setup-core.js" ;
import type { CoreConfig } from
"./types.js" ;
function applyOpsAccountConfig(cfg: CoreConfig): CoreConfig {
return matrixSetupAdapter.applyAccountConfig({
cfg,
accountId:
"ops" ,
input: {
name:
"Ops" ,
homeserver:
"https://matrix.example.org ",
accessToken:
"ops-token" ,
},
}) as CoreConfig;
}
function expectPromotedDefaultAccount(next: CoreConfig):
void {
expect(next.channels?.matrix?.accounts?.
Default ).toMatchObject({
enabled:
true ,
deviceName:
"Legacy raw key" ,
homeserver:
"https://matrix.example.org ",
userId:
"@default:example.org" ,
accessToken:
"default-token" ,
avatarUrl:
"mxc://example.org/default-avatar",
});
expect(next.channels?.matrix?.accounts?.
default ).toBeUndefined();
}
function expectOpsAccount(next: CoreConfig):
void {
expect(next.channels?.matrix?.accounts?.ops).toMatchObject({
name:
"Ops" ,
enabled:
true ,
homeserver:
"https://matrix.example.org ",
accessToken:
"ops-token" ,
});
}
function makeFakeSetupWizard(
overrides: Partial<ChannelSetupWizardAdapter> = {},
): ChannelSetupWizardAdapter {
return {
channel:
"matrix" ,
getStatus: vi.fn(async () => ({
channel:
"matrix" ,
configured:
false ,
statusLines: [],
})),
configure: vi.fn(async ({ cfg }) => ({ cfg })),
...overrides,
} as ChannelSetupWizardAdapter;
}
describe(
"createMatrixSetupWizardProxy" , () => {
it(
"does not load the setup surface when constructing the proxy" , () => {
const loader = vi.fn(async () => ({ matrixSetupWizard: makeFakeSetupWizard() }));
const proxy = createMatrixSetupWizardProxy(loader);
expect(proxy.channel).toBe(
"matrix" );
expect(loader).not.toHaveBeenCalled();
});
it(
"loads the setup surface when setup status is requested" , async () => {
const status = {
channel:
"matrix" as
const ,
configured:
true ,
statusLines: [
"Matrix: configured" ],
};
const getStatus = vi.fn(async () => status);
const configure = vi.fn(async ({ cfg }) => ({ cfg }));
const loader = vi.fn(async () => ({
matrixSetupWizard: makeFakeSetupWizard({ configure, getStatus }),
}));
const proxy = createMatrixSetupWizardProxy(loader);
const cfg = { channels: { matrix: {} } } as CoreConfig;
const result = await proxy.getStatus({ cfg, accountOverrides: {} });
const configured = await proxy.configure({
cfg,
runtime: {} as never,
prompter: {} as never,
forceAllowFrom:
false ,
accountOverrides: {},
shouldPromptAccountIds:
false ,
});
expect(loader).toHaveBeenCalledTimes(
1 );
expect(getStatus).toHaveBeenCalledWith({ cfg, accountOverrides: {} });
expect(configure).toHaveBeenCalledTimes(
1 );
expect(result).toBe(status);
expect(configured).toEqual({ cfg });
});
it(
"keeps sync dmPolicy helpers local and lazy-loads only promptAllowFrom" , async () => {
const promptAllowFrom = vi.fn(async ({ cfg }) => cfg);
const loader = vi.fn(async () => ({
matrixSetupWizard: makeFakeSetupWizard({
dmPolicy: {
label:
"Matrix" ,
channel:
"matrix" ,
policyKey:
"unused" ,
allowFromKey:
"unused" ,
getCurrent: () =>
"pairing" ,
setPolicy: (cfg) => cfg,
promptAllowFrom,
},
}),
}));
const proxy = createMatrixSetupWizardProxy(loader);
const cfg = {
channels: {
matrix: {
accounts: {
ops: {
dm: {
allowFrom: [
" @ops:example.org " ,
"" ,
"*" ],
},
},
},
},
},
} as CoreConfig;
expect(proxy.dmPolicy?.getCurrent(cfg,
"ops" )).toBe(
"pairing" );
const next = proxy.dmPolicy?.setPolicy(cfg,
"open" ,
"ops" ) as CoreConfig;
expect(next.channels?.matrix?.accounts?.ops?.dm).toMatchObject({
policy:
"open" ,
allowFrom: [
"@ops:example.org" ,
"*" ],
});
expect(loader).not.toHaveBeenCalled();
await proxy.dmPolicy?.promptAllowFrom?.({
cfg,
prompter: {} as never,
});
expect(loader).toHaveBeenCalledTimes(
1 );
expect(promptAllowFrom).toHaveBeenCalledTimes(
1 );
});
it(
"removes wildcard allowFrom when switching from open to a restrictive policy" , () => {
const loader = vi.fn(async () => ({ matrixSetupWizard: makeFakeSetupWizard() }));
const proxy = createMatrixSetupWizardProxy(loader);
const cfg = {
channels: {
matrix: {
accounts: {
ops: {
dm: {
policy:
"open" ,
allowFrom: [
"*" ,
" @ops:example.org " ],
},
},
},
},
},
} as CoreConfig;
const next = proxy.dmPolicy?.setPolicy(cfg,
"allowlist" ,
"ops" ) as CoreConfig;
expect(next.channels?.matrix?.accounts?.ops?.dm).toMatchObject({
policy:
"allowlist" ,
allowFrom: [
"@ops:example.org" ],
});
expect(loader).not.toHaveBeenCalled();
});
});
describe(
"matrixSetupAdapter" , () => {
it(
"moves legacy default config before writing a named account" , () => {
const cfg = {
channels: {
matrix: {
homeserver:
"https://matrix.example.org ",
userId:
"@default:example.org" ,
accessToken:
"default-token" ,
deviceName:
"Default device" ,
},
},
} as CoreConfig;
const next = matrixSetupAdapter.applyAccountConfig({
cfg,
accountId:
"ops" ,
input: {
name:
"Ops" ,
homeserver:
"https://matrix.example.org ",
userId:
"@ops:example.org" ,
accessToken:
"ops-token" ,
},
}) as CoreConfig;
expect(next.channels?.matrix?.homeserver).toBeUndefined();
expect(next.channels?.matrix?.userId).toBeUndefined();
expect(next.channels?.matrix?.accessToken).toBeUndefined();
expect(next.channels?.matrix?.accounts?.
default ).toMatchObject({
homeserver:
"https://matrix.example.org ",
userId:
"@default:example.org" ,
accessToken:
"default-token" ,
deviceName:
"Default device" ,
});
expect(next.channels?.matrix?.accounts?.ops).toMatchObject({
name:
"Ops" ,
enabled:
true ,
homeserver:
"https://matrix.example.org ",
userId:
"@ops:example.org" ,
accessToken:
"ops-token" ,
});
});
it(
"reuses an existing raw default-account key during promotion" , () => {
const cfg = {
channels: {
matrix: {
defaultAccount:
"default" ,
homeserver:
"https://matrix.example.org ",
userId:
"@default:example.org" ,
accessToken:
"default-token" ,
avatarUrl:
"mxc://example.org/default-avatar",
accounts: {
Default : {
enabled:
true ,
deviceName:
"Legacy raw key" ,
},
},
},
},
} as CoreConfig;
const next = applyOpsAccountConfig(cfg);
expectPromotedDefaultAccount(next);
expectOpsAccount(next);
});
it(
"reuses an existing raw default-like key during promotion when defaultAccount is unset" ,
() => {
const cfg = {
channels: {
matrix: {
homeserver: "https://matrix.example.org ",
userId: "@default:example.org" ,
accessToken: "default-token" ,
avatarUrl: "mxc://example.org/default-avatar",
accounts: {
Default : {
enabled: true ,
deviceName: "Legacy raw key" ,
},
support: {
homeserver: "https://matrix.example.org ",
accessToken: "support-token" ,
},
},
},
},
} as CoreConfig;
const next = applyOpsAccountConfig(cfg);
expectPromotedDefaultAccount(next);
expect(next.channels?.matrix?.accounts?.support).toMatchObject({
homeserver: "https://matrix.example.org ",
accessToken: "support-token" ,
});
expectOpsAccount(next);
});
it("clears stored auth fields when switching an account to env-backed auth" , () => {
const cfg = {
channels: {
matrix: {
accounts: {
ops: {
name: "Ops" ,
homeserver: "https://matrix.example.org ",
proxy: "http://127.0.0.1:7890 ",
userId: "@ops:example.org" ,
accessToken: "ops-token" ,
password: "secret" ,
deviceId: "DEVICE" ,
deviceName: "Ops device" ,
},
},
},
},
} as CoreConfig;
const next = matrixSetupAdapter.applyAccountConfig({
cfg,
accountId: "ops" ,
input: {
name: "Ops" ,
useEnv: true ,
},
}) as CoreConfig;
expect(next.channels?.matrix?.accounts?.ops).toMatchObject({
name: "Ops" ,
enabled: true ,
});
expect(next.channels?.matrix?.accounts?.ops?.homeserver).toBeUndefined();
expect(next.channels?.matrix?.accounts?.ops?.proxy).toBeUndefined();
expect(next.channels?.matrix?.accounts?.ops?.userId).toBeUndefined();
expect(next.channels?.matrix?.accounts?.ops?.accessToken).toBeUndefined();
expect(next.channels?.matrix?.accounts?.ops?.password).toBeUndefined();
expect(next.channels?.matrix?.accounts?.ops?.deviceId).toBeUndefined();
expect(next.channels?.matrix?.accounts?.ops?.deviceName).toBeUndefined();
});
it("keeps avatarUrl when switching an account to env-backed auth" , () => {
const cfg = {
channels: {
matrix: {
accounts: {
ops: {
name: "Ops" ,
homeserver: "https://matrix.example.org ",
accessToken: "ops-token" ,
},
},
},
},
} as CoreConfig;
const next = matrixSetupAdapter.applyAccountConfig({
cfg,
accountId: "ops" ,
input: {
name: "Ops" ,
useEnv: true ,
avatarUrl: " mxc://example.org/ops-avatar ",
},
}) as CoreConfig;
expect(next.channels?.matrix?.accounts?.ops).toMatchObject({
name: "Ops" ,
enabled: true ,
avatarUrl: "mxc://example.org/ops-avatar",
});
expect(next.channels?.matrix?.accounts?.ops?.homeserver).toBeUndefined();
expect(next.channels?.matrix?.accounts?.ops?.accessToken).toBeUndefined();
});
it("stores proxy in account setup updates" , () => {
const next = matrixSetupAdapter.applyAccountConfig({
cfg: {} as CoreConfig,
accountId: "ops" ,
input: {
homeserver: "https://matrix.example.org ",
accessToken: "ops-token" ,
proxy: "http://127.0.0.1:7890 ",
},
}) as CoreConfig;
expect(next.channels?.matrix?.accounts?.ops).toMatchObject({
enabled: true ,
homeserver: "https://matrix.example.org ",
accessToken: "ops-token" ,
proxy: "http://127.0.0.1:7890 ",
});
});
it("stores avatarUrl from setup input on the target account" , () => {
const next = matrixSetupAdapter.applyAccountConfig({
cfg: {} as CoreConfig,
accountId: "ops" ,
input: {
homeserver: "https://matrix.example.org ",
accessToken: "ops-token" ,
avatarUrl: " mxc://example.org/ops-avatar ",
},
}) as CoreConfig;
expect(next.channels?.matrix?.accounts?.ops).toMatchObject({
enabled: true ,
homeserver: "https://matrix.example.org ",
accessToken: "ops-token" ,
avatarUrl: "mxc://example.org/ops-avatar",
});
});
it("rejects unsupported avatar URL schemes during setup validation" , () => {
const validationError = matrixSetupAdapter.validateInput?.({
cfg: {} as CoreConfig,
accountId: "ops" ,
input: {
homeserver: "https://matrix.example.org ",
accessToken: "ops-token" ,
avatarUrl: "file:///tmp/avatar.png",
},
});
expect(validationError).toBe("Matrix avatar URL must be an mxc:// URI or an http(s) URL.");
});
it("stores canonical dangerous private-network opt-in from setup input" , () => {
const next = matrixSetupAdapter.applyAccountConfig({
cfg: {} as CoreConfig,
accountId: "ops" ,
input: {
homeserver: "http://matrix.internal:8008 ",
accessToken: "ops-token" ,
dangerouslyAllowPrivateNetwork: true ,
},
}) as CoreConfig;
expect(next.channels?.matrix?.accounts?.ops).toMatchObject({
enabled: true ,
homeserver: "http://matrix.internal:8008 ",
accessToken: "ops-token" ,
network: {
dangerouslyAllowPrivateNetwork: true ,
},
});
});
it("keeps top-level block streaming as a shared default when named accounts already exist" , () => {
const cfg = {
channels: {
matrix: {
homeserver: "https://matrix.example.org ",
userId: "@default:example.org" ,
accessToken: "default-token" ,
blockStreaming: true ,
accounts: {
support: {
homeserver: "https://matrix.example.org ",
userId: "@support:example.org" ,
accessToken: "support-token" ,
},
},
},
},
} as CoreConfig;
const next = matrixSetupAdapter.applyAccountConfig({
cfg,
accountId: "ops" ,
input: {
name: "Ops" ,
homeserver: "https://matrix.example.org ",
userId: "@ops:example.org" ,
accessToken: "ops-token" ,
},
}) as CoreConfig;
expect(next.channels?.matrix?.blockStreaming).toBe(true );
expect(next.channels?.matrix?.accounts?.ops).toMatchObject({
name: "Ops" ,
enabled: true ,
homeserver: "https://matrix.example.org ",
userId: "@ops:example.org" ,
accessToken: "ops-token" ,
});
expect(next.channels?.matrix?.accounts?.ops?.blockStreaming).toBeUndefined();
});
});
Messung V0.5 in Prozent C=93 H=100 G=96
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet am 2026-06-07)
¤
*© Formatika GbR, Deutschland