This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
import { beforeEach, describe, expect, test } from 'bun:test';
|
||||
|
||||
import { MessageFreshnessDetector } from './messageFreshness';
|
||||
|
||||
import type { Message } from '@opencode-ai/sdk/v2';
|
||||
|
||||
const makeAssistantMessage = (id: string, created: number): Message =>
|
||||
({
|
||||
id,
|
||||
role: 'assistant',
|
||||
sessionID: 'session-a',
|
||||
time: { created },
|
||||
}) as unknown as Message;
|
||||
|
||||
describe('MessageFreshnessDetector.shouldAnimateMessage', () => {
|
||||
let detector: MessageFreshnessDetector;
|
||||
|
||||
beforeEach(() => {
|
||||
detector = MessageFreshnessDetector.getInstance();
|
||||
detector.clearAll();
|
||||
});
|
||||
|
||||
test('fresh message animates once and is recorded as seen', () => {
|
||||
detector.recordSessionStart('session-a');
|
||||
const message = makeAssistantMessage('msg-fresh', Date.now());
|
||||
|
||||
expect(detector.shouldAnimateMessage(message, 'session-a')).toBe(true);
|
||||
expect(detector.hasBeenAnimated('msg-fresh')).toBe(true);
|
||||
});
|
||||
|
||||
test('regression #2124: fresh message does not re-animate when returning to the session', () => {
|
||||
detector.recordSessionStart('session-a');
|
||||
const message = makeAssistantMessage('msg-fresh', Date.now());
|
||||
|
||||
// First visit: the message is fresh and animates.
|
||||
expect(detector.shouldAnimateMessage(message, 'session-a')).toBe(true);
|
||||
|
||||
// User switches away and back; ChatViewport remounts and re-evaluates
|
||||
// before recordSessionStart runs again, so the old session start time
|
||||
// is still in effect. The message must not animate a second time.
|
||||
expect(detector.shouldAnimateMessage(message, 'session-a')).toBe(false);
|
||||
});
|
||||
|
||||
test('stale history message never animates and is recorded as seen', () => {
|
||||
detector.recordSessionStart('session-a');
|
||||
const message = makeAssistantMessage('msg-old', Date.now() - 60_000);
|
||||
|
||||
expect(detector.shouldAnimateMessage(message, 'session-a')).toBe(false);
|
||||
expect(detector.hasBeenAnimated('msg-old')).toBe(true);
|
||||
expect(detector.shouldAnimateMessage(message, 'session-a')).toBe(false);
|
||||
});
|
||||
|
||||
test('message evaluated without a recorded session start does not animate and is recorded', () => {
|
||||
const message = makeAssistantMessage('msg-no-session', Date.now());
|
||||
|
||||
expect(detector.shouldAnimateMessage(message, 'session-a')).toBe(false);
|
||||
expect(detector.hasBeenAnimated('msg-no-session')).toBe(true);
|
||||
|
||||
// Recording the session start afterwards must not resurrect the animation.
|
||||
detector.recordSessionStart('session-a');
|
||||
expect(detector.shouldAnimateMessage(message, 'session-a')).toBe(false);
|
||||
});
|
||||
|
||||
test('non-assistant messages never animate', () => {
|
||||
detector.recordSessionStart('session-a');
|
||||
const message = {
|
||||
id: 'msg-user',
|
||||
role: 'user',
|
||||
sessionID: 'session-a',
|
||||
time: { created: Date.now() },
|
||||
} as unknown as Message;
|
||||
|
||||
expect(detector.shouldAnimateMessage(message, 'session-a')).toBe(false);
|
||||
});
|
||||
|
||||
test('a new fresh message still animates after older fresh messages were seen', () => {
|
||||
detector.recordSessionStart('session-a');
|
||||
const first = makeAssistantMessage('msg-first', Date.now());
|
||||
const second = makeAssistantMessage('msg-second', Date.now());
|
||||
|
||||
expect(detector.shouldAnimateMessage(first, 'session-a')).toBe(true);
|
||||
expect(detector.shouldAnimateMessage(second, 'session-a')).toBe(true);
|
||||
expect(detector.shouldAnimateMessage(second, 'session-a')).toBe(false);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user