mirror of
https://wget.la/https://github.com/Wxw-Gu/WechatExplorer
synced 2026-10-05 21:05:39 +08:00
feat: 退群监控接入自动化能力统一管理, 支持发送个人/文件传输助手/指定群聊
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
import { readFileSync } from 'fs-extra'
|
||||
import { join } from 'path'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
import { createDefaultLeaveNotificationRule } from '../../src/shared/automation'
|
||||
import { GROUP_EXIT_NOTIFICATION_TEMPLATE } from '../../src/shared/group-exit-monitor'
|
||||
|
||||
/**
|
||||
* E2E main 替身(`tests/e2e/support/electron-main.cjs`)的**默认值契约**。
|
||||
*
|
||||
* 替身扮演"一个全新安装的 main 进程"。它里面的默认值必须与真实默认值逐字一致,
|
||||
* 否则 E2E 与截图验证的就是一个**不存在的世界**。
|
||||
*
|
||||
* 这个契约是被真实事故逼出来的:迁移时把默认目标从"文件传输助手"改成"当前群聊"、
|
||||
* 并往默认模板里加了「群聊: {groupName}」一行,但替身没跟着改 ——
|
||||
* 于是截图里看到的是"当前群聊没被选中、模板也没有群聊行",
|
||||
* 而组件测试却全绿(组件测试用的是内存 mock,不是替身)。
|
||||
*/
|
||||
|
||||
const DOUBLE_PATH = join(process.cwd(), 'tests/e2e/support/electron-main.cjs')
|
||||
|
||||
/**
|
||||
* 取出替身里整条退群通知规则(该声明在文件里只出现一次)。
|
||||
*
|
||||
* 起点取 `let leaveNotificationRule = {` 而不是 `leaveNotification:` ——
|
||||
* `enabled` / `ruleType` / `cooldownSeconds` 都在嵌套的 leaveNotification 之前。
|
||||
*/
|
||||
function leaveNotificationBlock(): string {
|
||||
const source = readFileSync(DOUBLE_PATH, 'utf8')
|
||||
const start = source.indexOf('let leaveNotificationRule = {')
|
||||
expect(start, '替身里找不到 leaveNotificationRule').toBeGreaterThan(-1)
|
||||
return source.slice(start)
|
||||
}
|
||||
|
||||
describe('E2E main 替身的默认值契约', () => {
|
||||
const defaults = createDefaultLeaveNotificationRule(0)
|
||||
|
||||
it('退群通知的默认目标与真实默认值一致', () => {
|
||||
const block = leaveNotificationBlock()
|
||||
const match = block.match(/target:\s*\{\s*type:\s*'([a-z_]+)'/)
|
||||
|
||||
expect(match?.[1]).toBe(defaults.leaveNotification?.target.type)
|
||||
})
|
||||
|
||||
it('退群通知的默认模板与真实默认值逐字一致', () => {
|
||||
const block = leaveNotificationBlock()
|
||||
const match = block.match(/template:\s*'((?:[^'\\]|\\.)*)'/)
|
||||
|
||||
expect(match, '替身里找不到 template 字面量').not.toBeNull()
|
||||
// 替身里是单引号 + \n 转义的 JS 字面量,反转义后与 shared 常量比对。
|
||||
const template = (match as RegExpMatchArray)[1].replace(/\\n/g, '\n')
|
||||
|
||||
expect(template).toBe(defaults.leaveNotification?.template)
|
||||
expect(template).toBe(GROUP_EXIT_NOTIFICATION_TEMPLATE)
|
||||
})
|
||||
|
||||
it('替身里必须存在群名占位符(否则截图看不出群名变量)', () => {
|
||||
expect(leaveNotificationBlock()).toContain('群聊: {groupName}')
|
||||
})
|
||||
|
||||
it('起停/冷却语义与真实默认值一致', () => {
|
||||
const block = leaveNotificationBlock()
|
||||
|
||||
expect(block).toMatch(/enabled:\s*true/)
|
||||
expect(block).toMatch(/ruleType:\s*'leave_notification'/)
|
||||
// 退群通知不套用消息型规则的冷却,否则两次退群会被并成一次。
|
||||
expect(block).toMatch(/cooldownSeconds:\s*0/)
|
||||
})
|
||||
|
||||
it('替身里的日报规则类型与真实分派一致', () => {
|
||||
const source = readFileSync(DOUBLE_PATH, 'utf8')
|
||||
expect(source).toContain("ruleType: 'daily_report'")
|
||||
})
|
||||
})
|
||||
@@ -73,14 +73,6 @@ describe('preload IPC contract', () => {
|
||||
expect(invoke).toHaveBeenLastCalledWith('group-exit-monitor:setEnabled', false)
|
||||
await api.setGroupExitMonitorGroups(['room@chatroom'])
|
||||
expect(invoke).toHaveBeenLastCalledWith('group-exit-monitor:setGroups', ['room@chatroom'])
|
||||
await api.setGroupExitMonitorGroups(['room@chatroom'], ['room@chatroom'])
|
||||
expect(invoke).toHaveBeenLastCalledWith(
|
||||
'group-exit-monitor:setGroups',
|
||||
['room@chatroom'],
|
||||
['room@chatroom']
|
||||
)
|
||||
await api.setGroupExitMonitorNotificationTemplate('用户: {user}')
|
||||
expect(invoke).toHaveBeenLastCalledWith('group-exit-monitor:setTemplate', '用户: {user}')
|
||||
await api.checkGroupExitMonitorNow()
|
||||
expect(invoke).toHaveBeenLastCalledWith('group-exit-monitor:checkNow')
|
||||
await api.clearGroupExitMonitorEvents()
|
||||
@@ -90,6 +82,24 @@ describe('preload IPC contract', () => {
|
||||
await api.listWechatActionLogs()
|
||||
expect(invoke).toHaveBeenLastCalledWith('wechat-action-log:list')
|
||||
|
||||
// 退群通知:保存走 singleton upsert,联系人候选由 main 侧过滤。
|
||||
const leaveDraft = {
|
||||
name: '退群通知',
|
||||
enabled: true,
|
||||
ruleType: 'leave_notification',
|
||||
trigger: 'message',
|
||||
scope: 'group',
|
||||
conditions: {},
|
||||
actions: [],
|
||||
cooldownSeconds: 0,
|
||||
replyDelaySeconds: 2,
|
||||
leaveNotification: { target: { type: 'file_transfer' }, template: '[退群监测]' }
|
||||
} as never
|
||||
await api.saveLeaveNotificationRule(leaveDraft)
|
||||
expect(invoke).toHaveBeenLastCalledWith('automation:saveLeaveNotificationRule', leaveDraft)
|
||||
await api.listSendableContacts()
|
||||
expect(invoke).toHaveBeenLastCalledWith('automation:listSendableContacts')
|
||||
|
||||
await api.getImage('fixture-md5', 'fixture.dat', 'fixture-session', {
|
||||
force: true,
|
||||
priority: 0
|
||||
|
||||
Reference in New Issue
Block a user