mirror of
https://wget.la/https://github.com/Wxw-Gu/WechatExplorer
synced 2026-10-04 03:01:42 +08:00
151 lines
5.0 KiB
TypeScript
151 lines
5.0 KiB
TypeScript
import { mkdtempSync, readJsonSync, rmSync } from 'fs-extra'
|
|
import { tmpdir } from 'os'
|
|
import { join } from 'path'
|
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
|
|
const mocks = vi.hoisted(() => ({
|
|
userData: '',
|
|
chat: {
|
|
getChatDb: vi.fn(),
|
|
getCurrentAccountRoot: vi.fn(() => 'fixture-account'),
|
|
isReady: vi.fn(() => true),
|
|
getGroupSnapshotAsync: vi.fn()
|
|
},
|
|
capability: {
|
|
getPersonalWechatSendCapability: vi.fn()
|
|
},
|
|
sender: {
|
|
send: vi.fn()
|
|
}
|
|
}))
|
|
|
|
vi.mock('electron', () => ({
|
|
app: { getPath: () => mocks.userData },
|
|
BrowserWindow: { getAllWindows: () => [] }
|
|
}))
|
|
vi.mock('../../src/main/services/chat-service', () => mocks.chat)
|
|
vi.mock('../../src/main/services/personal-wechat-capability-service', () => ({
|
|
personalWechatCapabilityService: mocks.capability
|
|
}))
|
|
vi.mock('../../src/main/services/personal-wechat-send-service', () => ({
|
|
personalWechatSendService: mocks.sender
|
|
}))
|
|
|
|
import { GroupExitMonitorService } from '../../src/main/services/group-exit-monitor-service'
|
|
|
|
const member = { wxid: 'wxid_member', wechatNickname: '微信名', groupNickname: '群内名' }
|
|
|
|
function installGroupDb(): void {
|
|
const client = {
|
|
getSessionsAsync: vi
|
|
.fn()
|
|
.mockResolvedValue([{ username: 'room@chatroom', nickname: '测试群' }]),
|
|
md5: vi.fn(() => 'room-md5')
|
|
}
|
|
mocks.chat.getChatDb.mockReturnValue({ getWcdb4Client: () => client })
|
|
}
|
|
|
|
describe('GroupExitMonitorService', () => {
|
|
const temporaryDirectories: string[] = []
|
|
|
|
beforeEach(() => {
|
|
mocks.userData = mkdtempSync(join(tmpdir(), 'tracememo-group-monitor-'))
|
|
temporaryDirectories.push(mocks.userData)
|
|
mocks.chat.getChatDb.mockReset()
|
|
mocks.chat.getCurrentAccountRoot.mockReset().mockReturnValue('fixture-account')
|
|
mocks.chat.isReady.mockReset().mockReturnValue(true)
|
|
mocks.chat.getGroupSnapshotAsync.mockReset()
|
|
mocks.capability.getPersonalWechatSendCapability.mockReset()
|
|
mocks.sender.send.mockReset()
|
|
})
|
|
|
|
afterEach(() => {
|
|
while (temporaryDirectories.length) {
|
|
rmSync(temporaryDirectories.pop()!, { recursive: true, force: true })
|
|
}
|
|
})
|
|
|
|
it('persists a validated custom template in the monitor state file', () => {
|
|
const service = new GroupExitMonitorService()
|
|
const template = '[退群监测]\n用户: {user}'
|
|
|
|
const state = service.setNotificationTemplate(template)
|
|
expect(state.notificationTemplate).toBe(template)
|
|
expect(readJsonSync(join(mocks.userData, 'group-exit-monitor.json')).notificationTemplate).toBe(
|
|
template
|
|
)
|
|
expect(() => service.setNotificationTemplate('用户: {unknown}')).toThrow('不支持的占位符')
|
|
})
|
|
|
|
it('keeps the previous baseline when a native snapshot contains null members', async () => {
|
|
installGroupDb()
|
|
mocks.chat.getGroupSnapshotAsync.mockResolvedValueOnce({
|
|
roomId: 'room@chatroom',
|
|
members: [member]
|
|
})
|
|
const service = new GroupExitMonitorService()
|
|
service.setMonitoredRoomIds(['room@chatroom'])
|
|
await service.start(true)
|
|
|
|
mocks.chat.getGroupSnapshotAsync.mockResolvedValueOnce({
|
|
roomId: 'room@chatroom',
|
|
members: null
|
|
})
|
|
const state = await service.checkNow()
|
|
|
|
expect(state.events).toEqual([])
|
|
expect(state.monitoredGroupCount).toBe(1)
|
|
})
|
|
|
|
it('returns from scope saving before the background baseline read completes', async () => {
|
|
installGroupDb()
|
|
mocks.chat.getGroupSnapshotAsync.mockResolvedValueOnce({
|
|
roomId: 'room@chatroom',
|
|
members: [member]
|
|
})
|
|
const service = new GroupExitMonitorService()
|
|
service.setMonitoredRoomIds(['room@chatroom'])
|
|
await service.start(true)
|
|
|
|
let release!: (snapshot: unknown) => void
|
|
mocks.chat.getGroupSnapshotAsync.mockReturnValueOnce(
|
|
new Promise((resolve) => {
|
|
release = resolve
|
|
})
|
|
)
|
|
const startedAt = Date.now()
|
|
const state = await service.setMonitoredRoomIds(['room@chatroom'])
|
|
|
|
expect(Date.now() - startedAt).toBeLessThan(250)
|
|
expect(state.monitoredRoomIds).toEqual(['room@chatroom'])
|
|
release({ roomId: 'room@chatroom', members: [member] })
|
|
})
|
|
|
|
it('renders the saved template before sending a group notification', async () => {
|
|
installGroupDb()
|
|
mocks.capability.getPersonalWechatSendCapability.mockResolvedValue({
|
|
ready: true,
|
|
capabilities: { text: true }
|
|
})
|
|
mocks.sender.send.mockResolvedValue({ success: true })
|
|
mocks.chat.getGroupSnapshotAsync
|
|
.mockResolvedValueOnce({
|
|
roomId: 'room@chatroom',
|
|
members: [member, { wxid: 'wxid_other', wechatNickname: '另一个人' }]
|
|
})
|
|
.mockResolvedValueOnce({ roomId: 'room@chatroom', members: [member] })
|
|
const service = new GroupExitMonitorService()
|
|
service.setNotificationTemplate('退群: {user}/{groupRemark}/{wxid}')
|
|
service.setMonitoredRoomIds(['room@chatroom'], ['room@chatroom'])
|
|
await service.start(true)
|
|
await service.checkNow()
|
|
|
|
expect(mocks.sender.send).toHaveBeenCalledWith({
|
|
type: 'text',
|
|
to: 'room@chatroom',
|
|
isGroup: true,
|
|
text: '退群: 另一个人/未设置/wxid_other'
|
|
})
|
|
})
|
|
})
|