mirror of
https://github.com/qingchencloud/clawpanel.git
synced 2026-05-29 04:10:00 +08:00
641 lines
21 KiB
JavaScript
641 lines
21 KiB
JavaScript
import test from 'node:test'
|
|
import assert from 'node:assert/strict'
|
|
|
|
import {
|
|
buildOpenClawChannelDiagnosis,
|
|
buildMessagingPlatformFormValues,
|
|
listPlatformAccounts,
|
|
mergeOpenClawMessagingPlatformConfig,
|
|
resolveMessagingCredentialValueForSave,
|
|
normalizeMessagingPlatformForm,
|
|
} from '../scripts/dev-api.js'
|
|
|
|
test('渠道保存会为 Telegram 补齐新版 OpenClaw 必填访问策略', () => {
|
|
const form = normalizeMessagingPlatformForm('telegram', {
|
|
botToken: '123:token',
|
|
})
|
|
|
|
assert.equal(form.botToken, '123:token')
|
|
assert.equal(form.dmPolicy, 'pairing')
|
|
assert.equal(form.groupPolicy, 'allowlist')
|
|
})
|
|
|
|
test('渠道保存会把旧 UI 策略值转换为 OpenClaw 支持的枚举', () => {
|
|
const form = normalizeMessagingPlatformForm('slack', {
|
|
mode: 'socket',
|
|
botToken: 'xoxb-token',
|
|
appToken: 'xapp-token',
|
|
dmPolicy: 'allow',
|
|
groupPolicy: 'mentioned',
|
|
})
|
|
|
|
assert.equal(form.dmPolicy, 'open')
|
|
assert.deepEqual(form.allowFrom, ['*'])
|
|
assert.equal(form.groupPolicy, 'open')
|
|
assert.equal(form.requireMention, true)
|
|
assert.equal(form.webhookPath, '/slack/events')
|
|
assert.equal(form.userTokenReadOnly, false)
|
|
})
|
|
|
|
test('渠道保存不会向不支持顶层 requireMention 的平台写入非法字段', () => {
|
|
const form = normalizeMessagingPlatformForm('signal', {
|
|
account: '+15551234567',
|
|
dmPolicy: 'deny',
|
|
groupPolicy: 'mentioned',
|
|
})
|
|
|
|
assert.equal(form.dmPolicy, 'disabled')
|
|
assert.equal(form.groupPolicy, 'open')
|
|
assert.equal(Object.hasOwn(form, 'requireMention'), false)
|
|
})
|
|
|
|
test('渠道保存会为飞书补齐新版内核要求的默认字段', () => {
|
|
const form = normalizeMessagingPlatformForm('feishu', {
|
|
appId: 'cli_a',
|
|
appSecret: 'secret',
|
|
domain: '',
|
|
})
|
|
|
|
assert.equal(form.domain, 'feishu')
|
|
assert.equal(form.connectionMode, 'websocket')
|
|
assert.equal(form.webhookPath, '/feishu/events')
|
|
assert.equal(form.dmPolicy, 'pairing')
|
|
assert.equal(form.groupPolicy, 'allowlist')
|
|
assert.equal(form.reactionNotifications, 'off')
|
|
assert.equal(form.typingIndicator, true)
|
|
assert.equal(form.resolveSenderNames, true)
|
|
})
|
|
|
|
test('渠道读取会把新版访问策略字段回显为表单可编辑值', () => {
|
|
const values = buildMessagingPlatformFormValues('telegram', {
|
|
botToken: '123:token',
|
|
dmPolicy: 'allowlist',
|
|
groupPolicy: 'disabled',
|
|
allowFrom: ['u-1', 'u-2'],
|
|
})
|
|
|
|
assert.equal(values.botToken, '123:token')
|
|
assert.equal(values.dmPolicy, 'allowlist')
|
|
assert.equal(values.groupPolicy, 'disabled')
|
|
assert.equal(values.allowFrom, 'u-1, u-2')
|
|
assert.equal(values.allowedUsers, 'u-1, u-2')
|
|
})
|
|
|
|
test('渠道读取会合并飞书账号凭证和根节点共享策略字段', () => {
|
|
const values = buildMessagingPlatformFormValues(
|
|
'feishu',
|
|
{
|
|
appId: 'cli_a',
|
|
appSecret: 'secret',
|
|
},
|
|
{
|
|
channelRoot: {
|
|
domain: 'lark',
|
|
connectionMode: 'websocket',
|
|
webhookPath: '/feishu/events',
|
|
dmPolicy: 'pairing',
|
|
groupPolicy: 'allowlist',
|
|
reactionNotifications: 'off',
|
|
typingIndicator: true,
|
|
resolveSenderNames: false,
|
|
},
|
|
},
|
|
)
|
|
|
|
assert.equal(values.appId, 'cli_a')
|
|
assert.equal(values.appSecret, 'secret')
|
|
assert.equal(values.domain, 'lark')
|
|
assert.equal(values.connectionMode, 'websocket')
|
|
assert.equal(values.webhookPath, '/feishu/events')
|
|
assert.equal(values.dmPolicy, 'pairing')
|
|
assert.equal(values.groupPolicy, 'allowlist')
|
|
assert.equal(values.reactionNotifications, 'off')
|
|
assert.equal(values.typingIndicator, 'true')
|
|
assert.equal(values.resolveSenderNames, 'false')
|
|
})
|
|
|
|
test('渠道读取飞书多账号时不会用根节点旧凭证覆盖账号凭证', () => {
|
|
const values = buildMessagingPlatformFormValues(
|
|
'feishu',
|
|
{
|
|
appId: 'account_app',
|
|
appSecret: 'account_secret',
|
|
dmPolicy: 'pairing',
|
|
},
|
|
{
|
|
channelRoot: {
|
|
appId: 'root_app',
|
|
appSecret: 'root_secret',
|
|
domain: 'lark',
|
|
groupPolicy: 'allowlist',
|
|
},
|
|
},
|
|
)
|
|
|
|
assert.equal(values.appId, 'account_app')
|
|
assert.equal(values.appSecret, 'account_secret')
|
|
assert.equal(values.domain, 'lark')
|
|
assert.equal(values.dmPolicy, 'pairing')
|
|
assert.equal(values.groupPolicy, 'allowlist')
|
|
})
|
|
|
|
test('渠道读取会把 open + requireMention 反向回显为仅提及时策略', () => {
|
|
const values = buildMessagingPlatformFormValues('slack', {
|
|
mode: 'socket',
|
|
botToken: 'xoxb-token',
|
|
appToken: 'xapp-token',
|
|
groupPolicy: 'open',
|
|
requireMention: true,
|
|
})
|
|
|
|
assert.equal(values.groupPolicy, 'mentioned')
|
|
assert.equal(values.requireMention, 'true')
|
|
})
|
|
|
|
test('Discord 渠道读取会回显 applicationId', () => {
|
|
const values = buildMessagingPlatformFormValues('discord', {
|
|
token: 'discord-token',
|
|
applicationId: '123456789012345678',
|
|
})
|
|
|
|
assert.equal(values.token, 'discord-token')
|
|
assert.equal(values.applicationId, '123456789012345678')
|
|
})
|
|
|
|
test('渠道保存会在用户改回所有群组时显式清除仅提及开关', () => {
|
|
const form = normalizeMessagingPlatformForm('slack', {
|
|
mode: 'socket',
|
|
botToken: 'xoxb-token',
|
|
appToken: 'xapp-token',
|
|
groupPolicy: 'open',
|
|
})
|
|
|
|
assert.equal(form.groupPolicy, 'open')
|
|
assert.equal(form.requireMention, false)
|
|
})
|
|
|
|
test('渠道读取会把 SecretRef 密钥显示为安全占位并携带原始对象', () => {
|
|
const secretRef = { source: 'env', provider: 'default', id: 'TELEGRAM_BOT_TOKEN' }
|
|
const values = buildMessagingPlatformFormValues('telegram', {
|
|
botToken: secretRef,
|
|
dmPolicy: 'pairing',
|
|
groupPolicy: 'allowlist',
|
|
})
|
|
|
|
assert.equal(values.botToken, 'SecretRef(env:default:TELEGRAM_BOT_TOKEN)')
|
|
assert.deepEqual(values.__secretRefs, { botToken: secretRef })
|
|
})
|
|
|
|
test('渠道保存时用户未改动 SecretRef 占位会保留原始密钥引用', () => {
|
|
const secretRef = { source: 'env', provider: 'default', id: 'SLACK_BOT_TOKEN' }
|
|
const value = resolveMessagingCredentialValueForSave({
|
|
form: { botToken: 'SecretRef(env:default:SLACK_BOT_TOKEN)' },
|
|
current: { botToken: secretRef },
|
|
key: 'botToken',
|
|
})
|
|
|
|
assert.deepEqual(value, secretRef)
|
|
})
|
|
|
|
test('渠道保存时用户输入新密钥会替换旧 SecretRef', () => {
|
|
const secretRef = { source: 'env', provider: 'default', id: 'DISCORD_BOT_TOKEN' }
|
|
const value = resolveMessagingCredentialValueForSave({
|
|
form: { token: 'new-discord-token' },
|
|
current: { token: secretRef },
|
|
key: 'token',
|
|
})
|
|
|
|
assert.equal(value, 'new-discord-token')
|
|
})
|
|
|
|
test('渠道账号列表会把 SecretRef 标识显示为安全占位', () => {
|
|
const accounts = listPlatformAccounts({
|
|
accounts: {
|
|
prod: {
|
|
appId: { source: 'env', provider: 'default', id: 'FEISHU_APP_ID' },
|
|
},
|
|
backup: {
|
|
clientId: { source: 'env', provider: 'default', id: 'DINGTALK_CLIENT_ID' },
|
|
},
|
|
},
|
|
})
|
|
|
|
assert.deepEqual(accounts, [
|
|
{ accountId: 'backup', appId: 'SecretRef(env:default:DINGTALK_CLIENT_ID)' },
|
|
{ accountId: 'prod', appId: 'SecretRef(env:default:FEISHU_APP_ID)' },
|
|
])
|
|
})
|
|
|
|
test('渠道保存时 clientId 未改动 SecretRef 占位会保留原始引用', () => {
|
|
const secretRef = { source: 'env', provider: 'default', id: 'DINGTALK_CLIENT_ID' }
|
|
const value = resolveMessagingCredentialValueForSave({
|
|
form: { clientId: 'SecretRef(env:default:DINGTALK_CLIENT_ID)' },
|
|
current: { clientId: secretRef },
|
|
key: 'clientId',
|
|
})
|
|
|
|
assert.deepEqual(value, secretRef)
|
|
})
|
|
|
|
test('OpenClaw 渠道保存带账号标识时会写入 accounts 而不是覆盖根配置', () => {
|
|
const cfg = {
|
|
channels: {
|
|
telegram: {
|
|
enabled: true,
|
|
botToken: 'root-token',
|
|
dmPolicy: 'pairing',
|
|
groupPolicy: 'allowlist',
|
|
},
|
|
discord: {
|
|
enabled: true,
|
|
token: 'root-discord',
|
|
groupPolicy: 'allowlist',
|
|
},
|
|
slack: {
|
|
enabled: true,
|
|
mode: 'socket',
|
|
botToken: 'root-slack',
|
|
appToken: 'root-app',
|
|
},
|
|
},
|
|
}
|
|
|
|
mergeOpenClawMessagingPlatformConfig(cfg, {
|
|
platform: 'telegram',
|
|
accountId: 'alerts',
|
|
form: { botToken: 'alerts-token', dmPolicy: 'allowlist', groupPolicy: 'disabled' },
|
|
})
|
|
mergeOpenClawMessagingPlatformConfig(cfg, {
|
|
platform: 'discord',
|
|
accountId: 'ops',
|
|
form: { token: 'ops-discord', guildId: 'guild-1', channelId: 'channel-1' },
|
|
})
|
|
mergeOpenClawMessagingPlatformConfig(cfg, {
|
|
platform: 'slack',
|
|
accountId: 'team-a',
|
|
form: { mode: 'socket', botToken: 'team-slack', appToken: 'team-app' },
|
|
})
|
|
|
|
assert.equal(cfg.channels.telegram.botToken, 'root-token')
|
|
assert.equal(cfg.channels.telegram.accounts.alerts.botToken, 'alerts-token')
|
|
assert.equal(cfg.channels.telegram.accounts.alerts.dmPolicy, 'allowlist')
|
|
assert.equal(cfg.channels.discord.token, 'root-discord')
|
|
assert.equal(cfg.channels.discord.accounts.ops.token, 'ops-discord')
|
|
assert.equal(cfg.channels.discord.accounts.ops.guilds['guild-1'].channels['channel-1'].allow, true)
|
|
assert.equal(cfg.channels.slack.botToken, 'root-slack')
|
|
assert.equal(cfg.channels.slack.accounts['team-a'].botToken, 'team-slack')
|
|
assert.equal(cfg.channels.slack.accounts['team-a'].appToken, 'team-app')
|
|
})
|
|
|
|
test('通用渠道诊断会指出 Telegram 缺少 Bot Token', () => {
|
|
const result = buildOpenClawChannelDiagnosis({
|
|
platform: 'telegram',
|
|
configExists: true,
|
|
channelEnabled: true,
|
|
form: {
|
|
dmPolicy: 'pairing',
|
|
groupPolicy: 'allowlist',
|
|
},
|
|
})
|
|
|
|
assert.equal(result.ok, false)
|
|
assert.equal(result.overallReady, false)
|
|
assert.equal(result.checks.find(item => item.id === 'credentials')?.ok, false)
|
|
assert.match(result.checks.find(item => item.id === 'credentials')?.detail || '', /Bot Token/)
|
|
})
|
|
|
|
test('通用渠道诊断在缺少渠道配置时不会误报渠道已禁用', () => {
|
|
const result = buildOpenClawChannelDiagnosis({
|
|
platform: 'telegram',
|
|
configExists: false,
|
|
channelEnabled: true,
|
|
form: {},
|
|
})
|
|
|
|
assert.equal(result.ok, false)
|
|
assert.equal(result.checks.find(item => item.id === 'config_exists')?.ok, false)
|
|
assert.equal(result.checks.find(item => item.id === 'channel_enabled')?.ok, true)
|
|
assert.match(result.checks.find(item => item.id === 'channel_enabled')?.detail || '', /未被显式禁用/)
|
|
})
|
|
|
|
test('通用渠道诊断会按 Slack 模式检查动态必填凭证', () => {
|
|
const socketResult = buildOpenClawChannelDiagnosis({
|
|
platform: 'slack',
|
|
configExists: true,
|
|
channelEnabled: true,
|
|
form: {
|
|
mode: 'socket',
|
|
botToken: 'xoxb-token',
|
|
},
|
|
})
|
|
const httpResult = buildOpenClawChannelDiagnosis({
|
|
platform: 'slack',
|
|
configExists: true,
|
|
channelEnabled: true,
|
|
form: {
|
|
mode: 'http',
|
|
botToken: 'xoxb-token',
|
|
signingSecret: 'secret',
|
|
},
|
|
})
|
|
|
|
assert.equal(socketResult.ok, false)
|
|
assert.match(socketResult.checks.find(item => item.id === 'credentials')?.detail || '', /App Token/)
|
|
assert.equal(httpResult.checks.find(item => item.id === 'credentials')?.ok, true)
|
|
})
|
|
|
|
test('通用渠道诊断会识别钉钉 Client ID 和 Client Secret', () => {
|
|
const result = buildOpenClawChannelDiagnosis({
|
|
platform: 'dingtalk',
|
|
configExists: true,
|
|
channelEnabled: true,
|
|
form: {
|
|
clientId: 'ding-app-key',
|
|
clientSecret: 'ding-secret',
|
|
},
|
|
verifyResult: {
|
|
valid: true,
|
|
details: ['已通过 accessToken 接口校验'],
|
|
},
|
|
})
|
|
|
|
assert.equal(result.ok, true)
|
|
assert.equal(result.overallReady, true)
|
|
assert.equal(result.checks.find(item => item.id === 'credentials')?.ok, true)
|
|
assert.equal(result.checks.find(item => item.id === 'online_verify')?.ok, true)
|
|
})
|
|
|
|
test('Zalo 渠道保存会补齐策略并保留 Bot Token 或 Token File', () => {
|
|
const tokenForm = normalizeMessagingPlatformForm('zalo', {
|
|
botToken: 'zalo-token',
|
|
groupAllowFrom: 'group-1, group-2',
|
|
mediaMaxMb: '25',
|
|
})
|
|
const tokenFileForm = normalizeMessagingPlatformForm('zalo', {
|
|
tokenFile: '/run/secrets/zalo-token',
|
|
})
|
|
|
|
assert.equal(tokenForm.botToken, 'zalo-token')
|
|
assert.equal(tokenForm.dmPolicy, 'pairing')
|
|
assert.equal(tokenForm.groupPolicy, 'allowlist')
|
|
assert.deepEqual(tokenForm.groupAllowFrom, ['group-1', 'group-2'])
|
|
assert.equal(tokenForm.mediaMaxMb, 25)
|
|
assert.equal(tokenFileForm.tokenFile, '/run/secrets/zalo-token')
|
|
})
|
|
|
|
test('OpenClaw 渠道保存会写入 Zalo 多账号配置', () => {
|
|
const cfg = { channels: {} }
|
|
|
|
mergeOpenClawMessagingPlatformConfig(cfg, {
|
|
platform: 'zalo',
|
|
accountId: 'vn',
|
|
form: {
|
|
botToken: 'zalo-token',
|
|
groupAllowFrom: 'thread-1',
|
|
mediaMaxMb: '30',
|
|
},
|
|
})
|
|
|
|
assert.equal(cfg.channels.zalo.defaultAccount, 'vn')
|
|
assert.equal(cfg.channels.zalo.accounts.vn.botToken, 'zalo-token')
|
|
assert.deepEqual(cfg.channels.zalo.accounts.vn.groupAllowFrom, ['thread-1'])
|
|
assert.equal(cfg.channels.zalo.accounts.vn.mediaMaxMb, 30)
|
|
})
|
|
|
|
test('Zalo 诊断接受 Bot Token 或 Token File 二选一', () => {
|
|
const tokenResult = buildOpenClawChannelDiagnosis({
|
|
platform: 'zalo',
|
|
configExists: true,
|
|
channelEnabled: true,
|
|
form: { botToken: 'zalo-token' },
|
|
})
|
|
const fileResult = buildOpenClawChannelDiagnosis({
|
|
platform: 'zalo',
|
|
configExists: true,
|
|
channelEnabled: true,
|
|
form: { tokenFile: '/run/secrets/zalo-token' },
|
|
})
|
|
const missingResult = buildOpenClawChannelDiagnosis({
|
|
platform: 'zalo',
|
|
configExists: true,
|
|
channelEnabled: true,
|
|
form: {},
|
|
})
|
|
|
|
assert.equal(tokenResult.checks.find(item => item.id === 'credentials')?.ok, true)
|
|
assert.equal(fileResult.checks.find(item => item.id === 'credentials')?.ok, true)
|
|
assert.equal(missingResult.checks.find(item => item.id === 'credentials')?.ok, false)
|
|
assert.match(missingResult.checks.find(item => item.id === 'credentials')?.detail || '', /Bot Token.*Token File/)
|
|
})
|
|
|
|
test('Zalo Personal 保存和诊断按二维码会话型渠道处理', () => {
|
|
const form = normalizeMessagingPlatformForm('zalouser', {
|
|
profile: 'work',
|
|
dangerouslyAllowNameMatching: 'true',
|
|
allowFrom: '12345, Alice',
|
|
groupAllowFrom: 'group-1',
|
|
historyLimit: '12',
|
|
})
|
|
const cfg = { channels: {} }
|
|
|
|
mergeOpenClawMessagingPlatformConfig(cfg, {
|
|
platform: 'zalouser',
|
|
accountId: 'work',
|
|
form,
|
|
})
|
|
const result = buildOpenClawChannelDiagnosis({
|
|
platform: 'zalouser',
|
|
configExists: true,
|
|
channelEnabled: true,
|
|
form: buildMessagingPlatformFormValues('zalouser', cfg.channels.zalouser.accounts.work),
|
|
})
|
|
|
|
assert.equal(cfg.channels.zalouser.defaultAccount, 'work')
|
|
assert.equal(cfg.channels.zalouser.accounts.work.profile, 'work')
|
|
assert.equal(cfg.channels.zalouser.accounts.work.dangerouslyAllowNameMatching, true)
|
|
assert.deepEqual(cfg.channels.zalouser.accounts.work.allowFrom, ['12345', 'Alice'])
|
|
assert.deepEqual(cfg.channels.zalouser.accounts.work.groupAllowFrom, ['group-1'])
|
|
assert.equal(cfg.channels.zalouser.accounts.work.historyLimit, 12)
|
|
assert.equal(result.checks.find(item => item.id === 'credentials')?.ok, true)
|
|
assert.equal(result.checks.find(item => item.id === 'credentials')?.title, '登录/会话配置')
|
|
})
|
|
|
|
test('LINE 渠道保存会写入双凭证组合并支持多账号', () => {
|
|
const cfg = { channels: {} }
|
|
|
|
mergeOpenClawMessagingPlatformConfig(cfg, {
|
|
platform: 'line',
|
|
accountId: 'jp',
|
|
form: {
|
|
tokenFile: '/run/secrets/line-token',
|
|
secretFile: '/run/secrets/line-secret',
|
|
allowFrom: 'U123, U456',
|
|
groupAllowFrom: 'C123',
|
|
groupPolicy: 'open',
|
|
mediaMaxMb: '25',
|
|
webhookPath: '/line/webhook',
|
|
},
|
|
})
|
|
|
|
const account = cfg.channels.line.accounts.jp
|
|
assert.equal(cfg.channels.line.defaultAccount, 'jp')
|
|
assert.equal(account.tokenFile, '/run/secrets/line-token')
|
|
assert.equal(account.secretFile, '/run/secrets/line-secret')
|
|
assert.deepEqual(account.allowFrom, ['U123', 'U456'])
|
|
assert.deepEqual(account.groupAllowFrom, ['C123'])
|
|
assert.equal(account.groupPolicy, 'open')
|
|
assert.equal(account.mediaMaxMb, 25)
|
|
assert.equal(account.webhookPath, '/line/webhook')
|
|
})
|
|
|
|
test('LINE 诊断要求 token 与 secret 两组凭证各满足一项', () => {
|
|
const ready = buildOpenClawChannelDiagnosis({
|
|
platform: 'line',
|
|
configExists: true,
|
|
channelEnabled: true,
|
|
form: {
|
|
channelAccessToken: 'line-token',
|
|
secretFile: '/run/secrets/line-secret',
|
|
},
|
|
})
|
|
const missingSecret = buildOpenClawChannelDiagnosis({
|
|
platform: 'line',
|
|
configExists: true,
|
|
channelEnabled: true,
|
|
form: {
|
|
channelAccessToken: 'line-token',
|
|
},
|
|
})
|
|
|
|
assert.equal(ready.checks.find(item => item.id === 'credentials')?.ok, true)
|
|
assert.equal(missingSecret.checks.find(item => item.id === 'credentials')?.ok, false)
|
|
assert.match(missingSecret.checks.find(item => item.id === 'credentials')?.detail || '', /Channel Secret.*Secret File/)
|
|
})
|
|
|
|
test('Mattermost 渠道保存会写入嵌套命令和网络配置', () => {
|
|
const cfg = { channels: {} }
|
|
|
|
mergeOpenClawMessagingPlatformConfig(cfg, {
|
|
platform: 'mattermost',
|
|
accountId: 'ops',
|
|
form: {
|
|
botToken: 'mattermost-token',
|
|
baseUrl: 'https://mattermost.example.com/',
|
|
groupPolicy: 'mentioned',
|
|
allowFrom: '@alice, bob',
|
|
groupAllowFrom: 'town-square',
|
|
callbackPath: '/api/channels/mattermost/ops',
|
|
callbackUrl: 'https://panel.example.com/api/channels/mattermost/ops',
|
|
dangerouslyAllowNameMatching: 'true',
|
|
dangerouslyAllowPrivateNetwork: 'true',
|
|
replyToMode: 'all',
|
|
},
|
|
})
|
|
|
|
const account = cfg.channels.mattermost.accounts.ops
|
|
assert.equal(cfg.channels.mattermost.defaultAccount, 'ops')
|
|
assert.equal(account.botToken, 'mattermost-token')
|
|
assert.equal(account.baseUrl, 'https://mattermost.example.com/')
|
|
assert.equal(account.groupPolicy, 'open')
|
|
assert.equal(account.requireMention, true)
|
|
assert.deepEqual(account.allowFrom, ['@alice', 'bob'])
|
|
assert.deepEqual(account.groupAllowFrom, ['town-square'])
|
|
assert.equal(account.commands.callbackPath, '/api/channels/mattermost/ops')
|
|
assert.equal(account.commands.callbackUrl, 'https://panel.example.com/api/channels/mattermost/ops')
|
|
assert.equal(account.network.dangerouslyAllowPrivateNetwork, true)
|
|
assert.equal(account.dangerouslyAllowNameMatching, true)
|
|
assert.equal(account.replyToMode, 'all')
|
|
})
|
|
|
|
test('Mattermost 诊断要求 Bot Token 和 Base URL', () => {
|
|
const missingBaseUrl = buildOpenClawChannelDiagnosis({
|
|
platform: 'mattermost',
|
|
configExists: true,
|
|
channelEnabled: true,
|
|
form: { botToken: 'mattermost-token' },
|
|
})
|
|
const ready = buildOpenClawChannelDiagnosis({
|
|
platform: 'mattermost',
|
|
configExists: true,
|
|
channelEnabled: true,
|
|
form: {
|
|
botToken: 'mattermost-token',
|
|
baseUrl: 'https://mattermost.example.com',
|
|
},
|
|
})
|
|
|
|
assert.equal(missingBaseUrl.checks.find(item => item.id === 'credentials')?.ok, false)
|
|
assert.match(missingBaseUrl.checks.find(item => item.id === 'credentials')?.detail || '', /Base URL/)
|
|
assert.equal(ready.checks.find(item => item.id === 'credentials')?.ok, true)
|
|
})
|
|
|
|
test('Discord 渠道保存会保留运行时需要的 applicationId', () => {
|
|
const cfg = { channels: {} }
|
|
|
|
mergeOpenClawMessagingPlatformConfig(cfg, {
|
|
platform: 'discord',
|
|
form: {
|
|
token: 'discord-token',
|
|
applicationId: '123456789012345678',
|
|
},
|
|
})
|
|
|
|
assert.equal(cfg.channels.discord.token, 'discord-token')
|
|
assert.equal(cfg.channels.discord.applicationId, '123456789012345678')
|
|
})
|
|
|
|
test('OpenClaw 渠道保存第一个命名账号时会固定 defaultAccount', () => {
|
|
const cfg = { channels: {} }
|
|
|
|
mergeOpenClawMessagingPlatformConfig(cfg, {
|
|
platform: 'telegram',
|
|
accountId: 'alerts',
|
|
form: { botToken: 'alerts-token' },
|
|
})
|
|
mergeOpenClawMessagingPlatformConfig(cfg, {
|
|
platform: 'telegram',
|
|
accountId: 'ops',
|
|
form: { botToken: 'ops-token' },
|
|
})
|
|
|
|
assert.equal(cfg.channels.telegram.defaultAccount, 'alerts')
|
|
assert.equal(cfg.channels.telegram.accounts.alerts.botToken, 'alerts-token')
|
|
assert.equal(cfg.channels.telegram.accounts.ops.botToken, 'ops-token')
|
|
})
|
|
|
|
test('OpenClaw 渠道保存命名账号时不会覆盖已有默认账号或根凭证默认账号', () => {
|
|
const explicitDefault = {
|
|
channels: {
|
|
discord: {
|
|
defaultAccount: 'ops',
|
|
accounts: { ops: { token: 'ops-token' } },
|
|
},
|
|
},
|
|
}
|
|
mergeOpenClawMessagingPlatformConfig(explicitDefault, {
|
|
platform: 'discord',
|
|
accountId: 'alerts',
|
|
form: { token: 'alerts-token' },
|
|
})
|
|
|
|
const rootDefault = {
|
|
channels: {
|
|
slack: {
|
|
mode: 'socket',
|
|
botToken: 'root-bot',
|
|
appToken: 'root-app',
|
|
},
|
|
},
|
|
}
|
|
mergeOpenClawMessagingPlatformConfig(rootDefault, {
|
|
platform: 'slack',
|
|
accountId: 'team-a',
|
|
form: { mode: 'socket', botToken: 'team-bot', appToken: 'team-app' },
|
|
})
|
|
|
|
assert.equal(explicitDefault.channels.discord.defaultAccount, 'ops')
|
|
assert.equal(explicitDefault.channels.discord.accounts.alerts.token, 'alerts-token')
|
|
assert.equal(rootDefault.channels.slack.defaultAccount, undefined)
|
|
assert.equal(rootDefault.channels.slack.accounts['team-a'].botToken, 'team-bot')
|
|
})
|