834 lines
22 KiB
TypeScript
834 lines
22 KiB
TypeScript
// Copyright 2021 Signal Messenger, LLC
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
import { assert } from 'chai';
|
|
import { v4 as generateUuid } from 'uuid';
|
|
|
|
import dataInterface from '../../sql/Client';
|
|
import { generateAci } from '../../types/ServiceId';
|
|
|
|
import type { ReactionType } from '../../types/Reactions';
|
|
import { DurationInSeconds } from '../../util/durations';
|
|
import type { MessageAttributesType } from '../../model-types.d';
|
|
import { ReadStatus } from '../../messages/MessageReadStatus';
|
|
|
|
const {
|
|
_removeAllMessages,
|
|
_removeAllReactions,
|
|
_getAllReactions,
|
|
_getAllMessages,
|
|
addReaction,
|
|
saveMessages,
|
|
getTotalUnreadForConversation,
|
|
getUnreadByConversationAndMarkRead,
|
|
getUnreadReactionsAndMarkRead,
|
|
} = dataInterface;
|
|
|
|
describe('sql/markRead', () => {
|
|
beforeEach(async () => {
|
|
await _removeAllMessages();
|
|
await _removeAllReactions();
|
|
});
|
|
|
|
it('properly finds and reads unread messages in current conversation', async () => {
|
|
assert.lengthOf(await _getAllMessages(), 0);
|
|
|
|
const start = Date.now();
|
|
const readAt = start + 20;
|
|
const conversationId = generateUuid();
|
|
const ourAci = generateAci();
|
|
|
|
const oldest: MessageAttributesType = {
|
|
id: generateUuid(),
|
|
body: 'message 1',
|
|
type: 'incoming',
|
|
conversationId,
|
|
sent_at: start + 1,
|
|
received_at: start + 1,
|
|
timestamp: start + 1,
|
|
readStatus: ReadStatus.Read,
|
|
};
|
|
const oldestUnread: MessageAttributesType = {
|
|
id: generateUuid(),
|
|
body: 'message 2',
|
|
type: 'incoming',
|
|
conversationId,
|
|
sent_at: start + 2,
|
|
received_at: start + 2,
|
|
timestamp: start + 2,
|
|
readStatus: ReadStatus.Unread,
|
|
};
|
|
const unreadInAnotherConvo: MessageAttributesType = {
|
|
id: generateUuid(),
|
|
body: 'message 3',
|
|
type: 'incoming',
|
|
conversationId: generateUuid(),
|
|
sent_at: start + 3,
|
|
received_at: start + 3,
|
|
timestamp: start + 3,
|
|
readStatus: ReadStatus.Unread,
|
|
};
|
|
const unread: MessageAttributesType = {
|
|
id: generateUuid(),
|
|
body: 'message 4',
|
|
type: 'incoming',
|
|
conversationId,
|
|
sent_at: start + 4,
|
|
received_at: start + 4,
|
|
timestamp: start + 4,
|
|
readStatus: ReadStatus.Unread,
|
|
};
|
|
const unreadStory: MessageAttributesType = {
|
|
id: generateUuid(),
|
|
body: 'message 5',
|
|
type: 'story',
|
|
conversationId,
|
|
sent_at: start + 5,
|
|
received_at: start + 5,
|
|
timestamp: start + 5,
|
|
readStatus: ReadStatus.Unread,
|
|
storyId: generateUuid(),
|
|
};
|
|
const unreadStoryReply: MessageAttributesType = {
|
|
id: generateUuid(),
|
|
body: 'message 6',
|
|
type: 'incoming',
|
|
conversationId,
|
|
sent_at: start + 6,
|
|
received_at: start + 6,
|
|
timestamp: start + 6,
|
|
readStatus: ReadStatus.Unread,
|
|
storyId: generateUuid(),
|
|
};
|
|
const newestUnread: MessageAttributesType = {
|
|
id: generateUuid(),
|
|
body: 'message 7',
|
|
type: 'incoming',
|
|
conversationId,
|
|
sent_at: start + 7,
|
|
received_at: start + 7,
|
|
timestamp: start + 7,
|
|
readStatus: ReadStatus.Unread,
|
|
};
|
|
|
|
await saveMessages(
|
|
[
|
|
oldest,
|
|
oldestUnread,
|
|
unreadInAnotherConvo,
|
|
unread,
|
|
unreadStory,
|
|
unreadStoryReply,
|
|
newestUnread,
|
|
],
|
|
{
|
|
forceSave: true,
|
|
ourAci,
|
|
}
|
|
);
|
|
|
|
assert.lengthOf(await _getAllMessages(), 7);
|
|
assert.strictEqual(
|
|
await getTotalUnreadForConversation(conversationId, {
|
|
storyId: undefined,
|
|
includeStoryReplies: false,
|
|
}),
|
|
3,
|
|
'no stories/unread count - before'
|
|
);
|
|
|
|
const markedRead = await getUnreadByConversationAndMarkRead({
|
|
conversationId,
|
|
newestUnreadAt: unreadStoryReply.received_at,
|
|
readAt,
|
|
includeStoryReplies: false,
|
|
});
|
|
|
|
assert.lengthOf(markedRead, 2, 'no stories/two messages marked read');
|
|
assert.strictEqual(
|
|
await getTotalUnreadForConversation(conversationId, {
|
|
storyId: undefined,
|
|
includeStoryReplies: false,
|
|
}),
|
|
1,
|
|
'no stories/unread count - after'
|
|
);
|
|
|
|
// Sorted in descending order
|
|
assert.strictEqual(
|
|
markedRead[0].id,
|
|
unread.id,
|
|
'no stories/first should be "unread" message'
|
|
);
|
|
assert.strictEqual(
|
|
markedRead[1].id,
|
|
oldestUnread.id,
|
|
'no stories/second should be oldestUnread'
|
|
);
|
|
|
|
const markedRead2 = await getUnreadByConversationAndMarkRead({
|
|
conversationId,
|
|
newestUnreadAt: newestUnread.received_at,
|
|
readAt,
|
|
includeStoryReplies: true,
|
|
});
|
|
|
|
assert.lengthOf(markedRead2, 2, 'with stories/two messages marked read');
|
|
|
|
assert.strictEqual(
|
|
markedRead2[0].id,
|
|
newestUnread.id,
|
|
'with stories/should be newestUnread'
|
|
);
|
|
assert.strictEqual(
|
|
markedRead2[1].id,
|
|
unreadStoryReply.id,
|
|
'with stories/should be unreadStoryReply'
|
|
);
|
|
|
|
assert.strictEqual(
|
|
await getTotalUnreadForConversation(conversationId, {
|
|
storyId: undefined,
|
|
includeStoryReplies: true,
|
|
}),
|
|
0,
|
|
'with stories/unread count'
|
|
);
|
|
});
|
|
|
|
it('properly finds and reads unread messages in story', async () => {
|
|
assert.lengthOf(await _getAllMessages(), 0);
|
|
|
|
const start = Date.now();
|
|
const readAt = start + 20;
|
|
const conversationId = generateUuid();
|
|
const storyId = generateUuid();
|
|
const ourAci = generateAci();
|
|
|
|
const message1: MessageAttributesType = {
|
|
id: generateUuid(),
|
|
body: 'message 1',
|
|
type: 'story',
|
|
conversationId,
|
|
sent_at: start + 1,
|
|
received_at: start + 1,
|
|
timestamp: start + 1,
|
|
readStatus: ReadStatus.Read,
|
|
storyId,
|
|
};
|
|
const message2: MessageAttributesType = {
|
|
id: generateUuid(),
|
|
body: 'message 2',
|
|
type: 'incoming',
|
|
conversationId,
|
|
sent_at: start + 2,
|
|
received_at: start + 2,
|
|
timestamp: start + 2,
|
|
readStatus: ReadStatus.Unread,
|
|
storyId,
|
|
};
|
|
const message3: MessageAttributesType = {
|
|
id: generateUuid(),
|
|
body: 'message 3',
|
|
type: 'incoming',
|
|
conversationId,
|
|
sent_at: start + 3,
|
|
received_at: start + 3,
|
|
timestamp: start + 3,
|
|
readStatus: ReadStatus.Unread,
|
|
storyId: generateUuid(),
|
|
};
|
|
const message4: MessageAttributesType = {
|
|
id: generateUuid(),
|
|
body: 'message 4',
|
|
type: 'incoming',
|
|
conversationId,
|
|
sent_at: start + 4,
|
|
received_at: start + 4,
|
|
timestamp: start + 4,
|
|
readStatus: ReadStatus.Unread,
|
|
storyId,
|
|
};
|
|
const message5: MessageAttributesType = {
|
|
id: generateUuid(),
|
|
body: 'message 5',
|
|
type: 'incoming',
|
|
conversationId,
|
|
sent_at: start + 5,
|
|
received_at: start + 5,
|
|
timestamp: start + 5,
|
|
readStatus: ReadStatus.Unread,
|
|
storyId: generateUuid(),
|
|
};
|
|
const message6: MessageAttributesType = {
|
|
id: generateUuid(),
|
|
body: 'message 6',
|
|
type: 'incoming',
|
|
conversationId,
|
|
sent_at: start + 6,
|
|
received_at: start + 6,
|
|
timestamp: start + 6,
|
|
readStatus: ReadStatus.Unread,
|
|
storyId: generateUuid(),
|
|
};
|
|
const message7: MessageAttributesType = {
|
|
id: generateUuid(),
|
|
body: 'message 7',
|
|
type: 'incoming',
|
|
conversationId,
|
|
sent_at: start + 7,
|
|
received_at: start + 7,
|
|
timestamp: start + 7,
|
|
readStatus: ReadStatus.Unread,
|
|
storyId,
|
|
};
|
|
|
|
await saveMessages(
|
|
[message1, message2, message3, message4, message5, message6, message7],
|
|
{
|
|
forceSave: true,
|
|
ourAci,
|
|
}
|
|
);
|
|
|
|
assert.lengthOf(await _getAllMessages(), 7);
|
|
|
|
const markedRead = await getUnreadByConversationAndMarkRead({
|
|
conversationId,
|
|
newestUnreadAt: message7.received_at,
|
|
readAt,
|
|
storyId,
|
|
includeStoryReplies: false,
|
|
});
|
|
|
|
assert.lengthOf(markedRead, 3, 'three messages marked read');
|
|
|
|
// Sorted in descending order
|
|
assert.strictEqual(
|
|
markedRead[0].id,
|
|
message7.id,
|
|
'first should be message7'
|
|
);
|
|
assert.strictEqual(
|
|
markedRead[1].id,
|
|
message4.id,
|
|
'first should be message4'
|
|
);
|
|
assert.strictEqual(
|
|
markedRead[2].id,
|
|
message2.id,
|
|
'second should be message2'
|
|
);
|
|
});
|
|
|
|
it('properly starts disappearing message timer, even if message is already read', async () => {
|
|
const now = Date.now();
|
|
assert.lengthOf(await _getAllMessages(), 0);
|
|
|
|
const start = Date.now();
|
|
const readAt = start + 20;
|
|
const conversationId = generateUuid();
|
|
const expireTimer = DurationInSeconds.fromSeconds(15);
|
|
const ourAci = generateAci();
|
|
|
|
const message1: MessageAttributesType = {
|
|
id: generateUuid(),
|
|
body: 'message 1',
|
|
type: 'incoming',
|
|
conversationId,
|
|
sent_at: start + 1,
|
|
received_at: start + 1,
|
|
timestamp: start + 1,
|
|
expireTimer,
|
|
expirationStartTimestamp: start + 1,
|
|
readStatus: ReadStatus.Read,
|
|
};
|
|
const message2: MessageAttributesType = {
|
|
id: generateUuid(),
|
|
body: 'message 2',
|
|
type: 'incoming',
|
|
conversationId,
|
|
sent_at: start + 2,
|
|
received_at: start + 2,
|
|
timestamp: start + 2,
|
|
expireTimer,
|
|
readStatus: ReadStatus.Read,
|
|
};
|
|
const message3: MessageAttributesType = {
|
|
id: generateUuid(),
|
|
body: 'message 3',
|
|
type: 'incoming',
|
|
conversationId: generateUuid(),
|
|
sent_at: start + 3,
|
|
received_at: start + 3,
|
|
timestamp: start + 3,
|
|
expireTimer,
|
|
readStatus: ReadStatus.Unread,
|
|
};
|
|
const message4: MessageAttributesType = {
|
|
id: generateUuid(),
|
|
body: 'message 4',
|
|
type: 'incoming',
|
|
conversationId,
|
|
sent_at: start + 4,
|
|
received_at: start + 4,
|
|
timestamp: start + 4,
|
|
expireTimer,
|
|
readStatus: ReadStatus.Unread,
|
|
};
|
|
const message5: MessageAttributesType = {
|
|
id: generateUuid(),
|
|
body: 'message 5',
|
|
type: 'incoming',
|
|
conversationId,
|
|
sent_at: start + 5,
|
|
received_at: start + 5,
|
|
timestamp: start + 5,
|
|
readStatus: ReadStatus.Unread,
|
|
};
|
|
|
|
await saveMessages([message1, message2, message3, message4, message5], {
|
|
forceSave: true,
|
|
ourAci,
|
|
});
|
|
|
|
assert.strictEqual(
|
|
await getTotalUnreadForConversation(conversationId, {
|
|
storyId: undefined,
|
|
includeStoryReplies: true,
|
|
}),
|
|
2,
|
|
'unread count'
|
|
);
|
|
assert.lengthOf(await _getAllMessages(), 5);
|
|
|
|
const markedRead = await getUnreadByConversationAndMarkRead({
|
|
conversationId,
|
|
newestUnreadAt: message4.received_at,
|
|
readAt,
|
|
includeStoryReplies: false,
|
|
now,
|
|
});
|
|
|
|
assert.lengthOf(markedRead, 1, 'one message marked read');
|
|
assert.strictEqual(
|
|
markedRead[0].id,
|
|
message4.id,
|
|
'first should be message4'
|
|
);
|
|
assert.strictEqual(
|
|
await getTotalUnreadForConversation(conversationId, {
|
|
storyId: undefined,
|
|
includeStoryReplies: true,
|
|
}),
|
|
1,
|
|
'unread count'
|
|
);
|
|
|
|
const allMessages = await _getAllMessages();
|
|
const sorted = allMessages.sort(
|
|
(left, right) => left.timestamp - right.timestamp
|
|
);
|
|
|
|
assert.strictEqual(sorted[1].id, message2.id, 'checking message 2');
|
|
assert.isAtMost(
|
|
sorted[1].expirationStartTimestamp ?? Infinity,
|
|
now,
|
|
'checking message 2 expirationStartTimestamp'
|
|
);
|
|
|
|
assert.strictEqual(sorted[3].id, message4.id, 'checking message 4');
|
|
assert.isAtMost(
|
|
sorted[3].expirationStartTimestamp ?? Infinity,
|
|
now,
|
|
'checking message 4 expirationStartTimestamp'
|
|
);
|
|
});
|
|
|
|
it('properly finds and reads unread reactions in current conversation', async () => {
|
|
assert.lengthOf(await _getAllReactions(), 0);
|
|
|
|
const start = Date.now();
|
|
const conversationId = generateUuid();
|
|
const storyId = generateUuid();
|
|
const ourAci = generateAci();
|
|
|
|
const pad: Array<MessageAttributesType> = Array.from({ length: 4 }, _ => {
|
|
return {
|
|
id: generateUuid(),
|
|
body: 'pad message',
|
|
type: 'incoming',
|
|
conversationId,
|
|
sent_at: start - 1,
|
|
received_at: start - 1,
|
|
timestamp: start - 1,
|
|
};
|
|
});
|
|
const message1: MessageAttributesType = {
|
|
id: generateUuid(),
|
|
body: 'message 1',
|
|
type: 'incoming',
|
|
conversationId,
|
|
sent_at: start + 1,
|
|
received_at: start + 1,
|
|
timestamp: start + 1,
|
|
};
|
|
const message2: MessageAttributesType = {
|
|
id: generateUuid(),
|
|
body: 'message 2',
|
|
type: 'incoming',
|
|
conversationId,
|
|
sent_at: start + 2,
|
|
received_at: start + 2,
|
|
timestamp: start + 2,
|
|
storyId,
|
|
};
|
|
const message3: MessageAttributesType = {
|
|
id: generateUuid(),
|
|
body: 'message 3',
|
|
type: 'incoming',
|
|
conversationId: generateUuid(),
|
|
sent_at: start + 3,
|
|
received_at: start + 3,
|
|
timestamp: start + 3,
|
|
};
|
|
const message4: MessageAttributesType = {
|
|
id: generateUuid(),
|
|
body: 'message 4',
|
|
type: 'incoming',
|
|
conversationId,
|
|
sent_at: start + 4,
|
|
received_at: start + 4,
|
|
timestamp: start + 4,
|
|
};
|
|
const message5: MessageAttributesType = {
|
|
id: generateUuid(),
|
|
body: 'message 5',
|
|
type: 'incoming',
|
|
conversationId,
|
|
sent_at: start + 5,
|
|
received_at: start + 5,
|
|
timestamp: start + 5,
|
|
};
|
|
|
|
await saveMessages(
|
|
[...pad, message1, message2, message3, message4, message5],
|
|
{
|
|
forceSave: true,
|
|
ourAci,
|
|
}
|
|
);
|
|
assert.lengthOf(await _getAllMessages(), pad.length + 5);
|
|
|
|
const reaction1: ReactionType = {
|
|
conversationId,
|
|
emoji: '🎉',
|
|
fromId: generateUuid(),
|
|
messageId: message1.id,
|
|
messageReceivedAt: message1.received_at,
|
|
targetAuthorAci: generateAci(),
|
|
targetTimestamp: start,
|
|
};
|
|
const reaction2: ReactionType = {
|
|
conversationId,
|
|
emoji: '🚀',
|
|
fromId: generateUuid(),
|
|
messageId: message2.id,
|
|
messageReceivedAt: message2.received_at,
|
|
targetAuthorAci: generateAci(),
|
|
targetTimestamp: start,
|
|
};
|
|
const reaction3: ReactionType = {
|
|
conversationId: generateUuid(),
|
|
emoji: '☀️',
|
|
fromId: generateUuid(),
|
|
messageId: message3.id,
|
|
messageReceivedAt: message3.received_at,
|
|
targetAuthorAci: generateAci(),
|
|
targetTimestamp: start,
|
|
};
|
|
const reaction4: ReactionType = {
|
|
conversationId,
|
|
emoji: '❤️🔥',
|
|
fromId: generateUuid(),
|
|
messageId: message4.id,
|
|
messageReceivedAt: message4.received_at,
|
|
targetAuthorAci: generateAci(),
|
|
targetTimestamp: start,
|
|
};
|
|
const reaction5: ReactionType = {
|
|
conversationId,
|
|
emoji: '🆒',
|
|
fromId: generateUuid(),
|
|
messageId: message5.id,
|
|
messageReceivedAt: message5.received_at,
|
|
targetAuthorAci: generateAci(),
|
|
targetTimestamp: start,
|
|
};
|
|
|
|
await addReaction(reaction1);
|
|
await addReaction(reaction2);
|
|
await addReaction(reaction3);
|
|
await addReaction(reaction4);
|
|
await addReaction(reaction5);
|
|
|
|
assert.lengthOf(await _getAllReactions(), 5);
|
|
const markedRead = await getUnreadReactionsAndMarkRead({
|
|
conversationId,
|
|
newestUnreadAt: reaction4.messageReceivedAt,
|
|
});
|
|
|
|
assert.lengthOf(markedRead, 2, 'two reactions marked read');
|
|
|
|
// Sorted in descending order
|
|
assert.strictEqual(
|
|
markedRead[0].messageId,
|
|
reaction4.messageId,
|
|
'first should be reaction4'
|
|
);
|
|
assert.strictEqual(
|
|
markedRead[1].messageId,
|
|
reaction1.messageId,
|
|
'second should be reaction1'
|
|
);
|
|
|
|
const markedRead2 = await getUnreadReactionsAndMarkRead({
|
|
conversationId,
|
|
newestUnreadAt: reaction5.messageReceivedAt,
|
|
});
|
|
|
|
assert.lengthOf(markedRead2, 1);
|
|
assert.strictEqual(
|
|
markedRead2[0].messageId,
|
|
reaction5.messageId,
|
|
'should be reaction5'
|
|
);
|
|
});
|
|
|
|
it('properly finds and reads unread reactions in story', async () => {
|
|
assert.lengthOf(await _getAllReactions(), 0);
|
|
|
|
const start = Date.now();
|
|
const conversationId = generateUuid();
|
|
const storyId = generateUuid();
|
|
const ourAci = generateAci();
|
|
|
|
const message1: MessageAttributesType = {
|
|
id: generateUuid(),
|
|
body: 'message 1',
|
|
type: 'incoming',
|
|
conversationId,
|
|
sent_at: start + 1,
|
|
received_at: start + 1,
|
|
timestamp: start + 1,
|
|
storyId,
|
|
};
|
|
const message2: MessageAttributesType = {
|
|
id: generateUuid(),
|
|
body: 'message 2',
|
|
type: 'incoming',
|
|
conversationId,
|
|
sent_at: start + 2,
|
|
received_at: start + 2,
|
|
timestamp: start + 2,
|
|
storyId: generateUuid(),
|
|
};
|
|
const message3: MessageAttributesType = {
|
|
id: generateUuid(),
|
|
body: 'message 3',
|
|
type: 'incoming',
|
|
conversationId: generateUuid(),
|
|
sent_at: start + 3,
|
|
received_at: start + 3,
|
|
timestamp: start + 3,
|
|
};
|
|
const message4: MessageAttributesType = {
|
|
id: generateUuid(),
|
|
body: 'message 4',
|
|
type: 'incoming',
|
|
conversationId,
|
|
sent_at: start + 4,
|
|
received_at: start + 4,
|
|
timestamp: start + 4,
|
|
storyId,
|
|
};
|
|
const message5: MessageAttributesType = {
|
|
id: generateUuid(),
|
|
body: 'message 5',
|
|
type: 'incoming',
|
|
conversationId,
|
|
sent_at: start + 5,
|
|
received_at: start + 5,
|
|
timestamp: start + 5,
|
|
storyId,
|
|
};
|
|
|
|
await saveMessages([message1, message2, message3, message4, message5], {
|
|
forceSave: true,
|
|
ourAci,
|
|
});
|
|
assert.lengthOf(await _getAllMessages(), 5);
|
|
|
|
const reaction1: ReactionType = {
|
|
conversationId,
|
|
emoji: '🎉',
|
|
fromId: generateUuid(),
|
|
messageId: message1.id,
|
|
messageReceivedAt: message1.received_at,
|
|
targetAuthorAci: generateAci(),
|
|
targetTimestamp: start,
|
|
};
|
|
const reaction2: ReactionType = {
|
|
conversationId,
|
|
emoji: '🚀',
|
|
fromId: generateUuid(),
|
|
messageId: message2.id,
|
|
messageReceivedAt: message2.received_at,
|
|
targetAuthorAci: generateAci(),
|
|
targetTimestamp: start,
|
|
};
|
|
const reaction3: ReactionType = {
|
|
conversationId: generateUuid(),
|
|
emoji: '☀️',
|
|
fromId: generateUuid(),
|
|
messageId: message3.id,
|
|
messageReceivedAt: message3.received_at,
|
|
targetAuthorAci: generateAci(),
|
|
targetTimestamp: start,
|
|
};
|
|
const reaction4: ReactionType = {
|
|
conversationId,
|
|
emoji: '❤️🔥',
|
|
fromId: generateUuid(),
|
|
messageId: message4.id,
|
|
messageReceivedAt: message4.received_at,
|
|
targetAuthorAci: generateAci(),
|
|
targetTimestamp: start,
|
|
};
|
|
const reaction5: ReactionType = {
|
|
conversationId,
|
|
emoji: '🆒',
|
|
fromId: generateUuid(),
|
|
messageId: message5.id,
|
|
messageReceivedAt: message5.received_at,
|
|
targetAuthorAci: generateAci(),
|
|
targetTimestamp: start,
|
|
};
|
|
|
|
await addReaction(reaction1);
|
|
await addReaction(reaction2);
|
|
await addReaction(reaction3);
|
|
await addReaction(reaction4);
|
|
await addReaction(reaction5);
|
|
|
|
assert.lengthOf(await _getAllReactions(), 5);
|
|
const markedRead = await getUnreadReactionsAndMarkRead({
|
|
conversationId,
|
|
newestUnreadAt: reaction4.messageReceivedAt,
|
|
storyId,
|
|
});
|
|
|
|
assert.lengthOf(markedRead, 2, 'two reactions marked read');
|
|
|
|
// Sorted in descending order
|
|
assert.strictEqual(
|
|
markedRead[0].messageId,
|
|
reaction4.messageId,
|
|
'first should be reaction4'
|
|
);
|
|
assert.strictEqual(
|
|
markedRead[1].messageId,
|
|
reaction1.messageId,
|
|
'second should be reaction1'
|
|
);
|
|
|
|
const markedRead2 = await getUnreadReactionsAndMarkRead({
|
|
conversationId,
|
|
newestUnreadAt: reaction5.messageReceivedAt,
|
|
storyId,
|
|
});
|
|
|
|
assert.lengthOf(markedRead2, 1);
|
|
assert.strictEqual(
|
|
markedRead2[0].messageId,
|
|
reaction5.messageId,
|
|
'should be reaction5'
|
|
);
|
|
});
|
|
|
|
it('does not include group story replies', async () => {
|
|
assert.lengthOf(await _getAllMessages(), 0);
|
|
|
|
const start = Date.now();
|
|
const readAt = start + 20;
|
|
const conversationId = generateUuid();
|
|
const storyId = generateUuid();
|
|
const ourAci = generateAci();
|
|
|
|
const message1: MessageAttributesType = {
|
|
id: generateUuid(),
|
|
body: 'message 1',
|
|
type: 'story',
|
|
conversationId,
|
|
sent_at: start + 1,
|
|
received_at: start + 1,
|
|
timestamp: start + 1,
|
|
readStatus: ReadStatus.Read,
|
|
};
|
|
const message2: MessageAttributesType = {
|
|
id: generateUuid(),
|
|
body: 'message 2',
|
|
type: 'incoming',
|
|
conversationId,
|
|
sent_at: start + 2,
|
|
received_at: start + 2,
|
|
timestamp: start + 2,
|
|
readStatus: ReadStatus.Unread,
|
|
storyId,
|
|
};
|
|
const message3: MessageAttributesType = {
|
|
id: generateUuid(),
|
|
body: 'message 3',
|
|
type: 'incoming',
|
|
conversationId,
|
|
sent_at: start + 3,
|
|
received_at: start + 3,
|
|
timestamp: start + 3,
|
|
readStatus: ReadStatus.Unread,
|
|
};
|
|
const message4: MessageAttributesType = {
|
|
id: generateUuid(),
|
|
body: 'message 4',
|
|
type: 'incoming',
|
|
conversationId,
|
|
sent_at: start + 4,
|
|
received_at: start + 4,
|
|
timestamp: start + 4,
|
|
readStatus: ReadStatus.Unread,
|
|
storyId,
|
|
};
|
|
|
|
await saveMessages([message1, message2, message3, message4], {
|
|
forceSave: true,
|
|
ourAci,
|
|
});
|
|
|
|
assert.lengthOf(await _getAllMessages(), 4);
|
|
|
|
const markedRead = await getUnreadByConversationAndMarkRead({
|
|
conversationId,
|
|
includeStoryReplies: false,
|
|
newestUnreadAt: message4.received_at,
|
|
readAt,
|
|
});
|
|
|
|
assert.lengthOf(markedRead, 1, '1 message marked read');
|
|
|
|
// Sorted in descending order
|
|
assert.strictEqual(
|
|
markedRead[0].id,
|
|
message3.id,
|
|
'first should be message3'
|
|
);
|
|
});
|
|
});
|