Files
Wxw-Gu ab3b3731b7 feat: 重构问问微信并完善知识库增量检索
统一问问微信与 Agent Hub 的查询链路
完善查询覆盖度、新鲜度和部分结果表达,避免索引滞后产生错误结论
基于会话实现真正的增量追新与历史补齐
支持后台同步、取消恢复、重启续传以及同步期间继续查询
优化知识库跨会话检索、同步状态、进度展示和侧栏布局
2026-09-11 17:44:48 +08:00

94 lines
3.7 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { describe, expect, it } from 'vitest'
import type { Message } from '../../src/shared/types'
import { buildMessageGroups } from '../../src/renderer/src/components/chat/messageGrouping'
import {
normalizeJumpMessageId,
resolveMessageJumpTarget
} from '../../src/renderer/src/components/chat/messageJump'
const message = (id: string, createTime: number, content = id): Message =>
({
id,
from: 'user',
type: '普通文本',
datetime: '',
content,
isSender: false,
createTime
}) as Message
/**
* 「跳转到原聊天」的定位契约。
*
* 必须**真的**落在那一条消息上,而不是"路由切过去了"。
* 秒级时间戳在群聊里对应多条消息,所以精确 id 必须优先。
*/
describe('resolveMessageJumpTarget', () => {
it('prefers the exact stable identity over the timestamp', () => {
const messages = [
message('m1', 1_700_000_000),
message('m2', 1_700_000_000),
message('m3', 1_700_000_000)
]
const groups = buildMessageGroups(messages)
// 三条消息同一秒:只有 id 能定位到正确的那一条。
const target = resolveMessageJumpTarget(groups, 1_700_000_000, 'm3')
expect(target).toMatchObject({ messageId: 'm3', exact: true })
})
it('normalizes the synthetic local: prefix on both sides', () => {
// 归档侧存的是 `local:42`,证据侧的 messageRef 解出来是 `42` —— 必须视为同一条。
const groups = buildMessageGroups([message('local:42', 1_700_000_000)])
expect(normalizeJumpMessageId('local:42')).toBe('42')
expect(resolveMessageJumpTarget(groups, undefined, '42')).toMatchObject({
messageId: 'local:42',
exact: true
})
// 反过来也一样(证据侧带前缀、归档侧不带)。
const plain = buildMessageGroups([message('42', 1_700_000_000)])
expect(resolveMessageJumpTarget(plain, undefined, 'local:42')).toMatchObject({
messageId: '42',
exact: true
})
})
it('returns the archive-side id so the highlight comparison cannot silently mismatch', () => {
const groups = buildMessageGroups([message('local:17078', 1_700_000_000)])
const target = resolveMessageJumpTarget(groups, undefined, '17078')
// 传进去的是归一化后的 `17078`,但返回的必须是归档侧真实出现的 `local:17078`:
// MessageGroup 用 message.id 直接比对高亮。
expect(target?.messageId).toBe('local:17078')
})
it('falls back to the first message at or after the timestamp for legacy evidence', () => {
const groups = buildMessageGroups([
message('old', 1_690_000_000),
message('hit', 1_700_000_100),
message('newer', 1_700_000_200)
])
expect(resolveMessageJumpTarget(groups, 1_700_000_000, undefined)).toMatchObject({
messageId: 'hit',
exact: false
})
})
it('reports nothing to jump to when the message no longer exists', () => {
const groups = buildMessageGroups([message('m1', 1_700_000_000)])
// 目标已被删除 / 清理,且时间戳晚于所有消息 → 调用方必须走诚实降级文案。
expect(resolveMessageJumpTarget(groups, 1_900_000_000, 'gone')).toBeNull()
expect(resolveMessageJumpTarget(groups, undefined, 'gone')).toBeNull()
expect(resolveMessageJumpTarget(groups, null, null)).toBeNull()
})
it('still resolves by id when the evidence carries no usable timestamp', () => {
const groups = buildMessageGroups([message('m1', 1_700_000_000), message('m2', 1_700_000_600)])
// 没有 createTime 的证据在真实数据里确实存在(老缓存),不能因此放弃定位。
expect(resolveMessageJumpTarget(groups, undefined, 'm1')).toMatchObject({
messageId: 'm1',
exact: true,
groupIndex: 0
})
})
})