fix(HH-576): normalize realtime message timestamps (#148)

Co-authored-by: Rogee <rogee@ipao.vip>
This commit is contained in:
Rogee
2026-08-24 10:16:22 +08:00
committed by GitHub
co-authored by rogee
parent 83e2a8ead6
commit b981cc6811
5 changed files with 202 additions and 7 deletions
@@ -158,6 +158,70 @@ describe('ActionCableConnector - Copilot Tests', () => {
).not.toHaveBeenCalled();
});
it('rejects malformed timestamps without updating conversation activity', async () => {
const currentMessage = {
id: 42,
conversation_id: 7,
content: 'current',
updated_at: '2026-08-24T02:00:00Z',
};
const state = {
allConversations: [
{ id: 7, messages: [currentMessage], last_activity_at: 200 },
],
selectedChatId: null,
};
useRealConversationDispatch(state);
await actionCable.onMessageCreated({
...currentMessage,
content: 'malformed',
updated_at: 'not-a-timestamp',
conversation: { last_activity_at: 300 },
});
expect(state.allConversations[0].messages[0]).toBe(currentMessage);
expect(state.allConversations[0].last_activity_at).toBe(200);
expect(
DashboardAudioNotificationHelper.onNewMessage
).not.toHaveBeenCalled();
});
it('keeps accepting events with a missing timestamp', async () => {
const state = {
allConversations: [
{
id: 7,
messages: [
{
id: 42,
conversation_id: 7,
content: 'current',
updated_at: '2026-08-24T02:00:00Z',
},
],
last_activity_at: 200,
},
],
selectedChatId: null,
};
useRealConversationDispatch(state);
const message = {
id: 42,
conversation_id: 7,
content: 'compatible update',
conversation: { last_activity_at: 300 },
};
await actionCable.onMessageCreated(message);
expect(state.allConversations[0].messages[0]).toEqual(message);
expect(state.allConversations[0].last_activity_at).toBe(300);
expect(DashboardAudioNotificationHelper.onNewMessage).toHaveBeenCalledWith(
message
);
});
it('skips dashboard side effects when the conversation mutation is a no-op', async () => {
setActivePinia(createPinia());
const state = { allConversations: [], selectedChatId: null };
@@ -193,7 +257,7 @@ describe('ActionCableConnector - Copilot Tests', () => {
{
id: 42,
conversation_id: 7,
updated_at: '2026-08-24T01:00:00Z',
updated_at: '1787533200',
},
],
last_activity_at: 100,
@@ -19,6 +19,7 @@ import {
handleVoiceCallUpdated,
syncConversationCallVisibility,
} from 'dashboard/helper/voice';
import { isNewerTimestamp } from 'shared/helpers/timeHelper';
export const hasMessageFailedWithExternalError = pendingMessage => {
// This helper is used to check if the message has failed with an external error.
@@ -41,9 +42,7 @@ const getStoredMessage = (conversation, message) => {
};
const isNewerMessage = (currentMessage, message) =>
!currentMessage?.updated_at ||
!message.updated_at ||
message.updated_at > currentMessage.updated_at;
isNewerTimestamp(currentMessage?.updated_at, message.updated_at);
// actions
const actions = {