9b4a25799f
Replace fixed ackText with a rule-based AckProvider that picks response templates by message type and intent (translate, summary, rewrite, poster, ppt, mindmap, code, search, schedule). Pure sync, zero I/O, auto-falls back to config.ackText on any error. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
77 lines
3.2 KiB
JavaScript
77 lines
3.2 KiB
JavaScript
import assert from 'node:assert/strict';
|
|
import test from 'node:test';
|
|
import { createWechatAdminService } from './wechat-admin.mjs';
|
|
|
|
test('wechat admin service lists and manages balance alerts', async () => {
|
|
const queries = [];
|
|
const pool = {
|
|
async query(sql, params = []) {
|
|
queries.push(sql);
|
|
if (sql.includes('FROM h5_balance_alert_subscriptions s')) {
|
|
return [[{ id: 'alert-1', user_id: 'user-1', username: 'alice', display_name: 'Alice', threshold_cents: 2000, channel: 'wechat', status: 'active', next_run_at: 1, last_run_at: null, last_notified_balance_cents: null, attempts: 0, last_error: null, source_text: '余额低于 20 元提醒我', created_at: 1, updated_at: 1 }]];
|
|
}
|
|
if (sql.includes('INSERT INTO h5_balance_alert_subscriptions')) {
|
|
return [{ affectedRows: 1 }, []];
|
|
}
|
|
if (sql.includes("UPDATE h5_balance_alert_subscriptions SET status = 'cancelled'")) {
|
|
return [{ affectedRows: 1 }, []];
|
|
}
|
|
if (sql.includes("UPDATE h5_balance_alert_subscriptions SET status = 'active'")) {
|
|
return [{ affectedRows: 1 }, []];
|
|
}
|
|
return [[]];
|
|
},
|
|
};
|
|
|
|
const service = createWechatAdminService(pool, { config: { enabled: true } });
|
|
const listed = await service.listBalanceAlerts();
|
|
assert.equal(listed.balanceAlerts.length, 1);
|
|
const created = await service.createBalanceAlert({ userId: 'user-1', thresholdCents: 2000, sourceText: '余额低于 20 元提醒我' });
|
|
assert.equal(created.ok, true);
|
|
assert.ok(queries.some((sql) => sql.includes('h5_balance_alert_subscriptions')));
|
|
});
|
|
|
|
test('wechat admin service creates multi-channel notification for all users', async () => {
|
|
const queries = [];
|
|
const wechatSent = [];
|
|
const pool = {
|
|
async query(sql) {
|
|
queries.push(sql);
|
|
if (sql.includes('SELECT id') && sql.includes('FROM h5_users')) {
|
|
return [[{ id: 'user-1' }, { id: 'user-2' }], []];
|
|
}
|
|
if (sql.includes('INSERT INTO h5_user_notifications')) {
|
|
return [{ affectedRows: 1 }, []];
|
|
}
|
|
if (sql.includes('FROM h5_user_notifications n')) {
|
|
return [[{ id: 'n1', user_id: 'user-1', username: 'john', display_name: 'John', channel: 'web', notification_type: 'manual', title: '测试通知', body: '这是一条网页端测试消息', status: 'unread', read_at: null, created_at: 1, updated_at: 1 }], []];
|
|
}
|
|
return [[], []];
|
|
},
|
|
};
|
|
|
|
const service = createWechatAdminService(pool, {
|
|
config: { enabled: true },
|
|
sendWechatTextToUser: async (userId, text) => {
|
|
wechatSent.push({ userId, text });
|
|
},
|
|
});
|
|
const created = await service.createWebNotification({
|
|
audience: 'all',
|
|
channels: ['web', 'wechat'],
|
|
notificationType: 'manual',
|
|
title: '测试通知',
|
|
body: '这是一条网页端测试消息',
|
|
});
|
|
assert.equal(created.ok, true);
|
|
assert.equal(created.created, 2);
|
|
assert.equal(created.wechatSent, 2);
|
|
assert.equal(created.targets, 2);
|
|
assert.equal(wechatSent.length, 2);
|
|
|
|
const listed = await service.listWebNotifications({ status: 'unread', limit: 10 });
|
|
assert.equal(listed.notifications.length, 1);
|
|
assert.equal(listed.notifications[0].title, '测试通知');
|
|
assert.ok(queries.some((sql) => sql.includes('h5_user_notifications')));
|
|
});
|