|
|
@@ -0,0 +1,429 @@
|
|
|
+import { expect } from 'chai'
|
|
|
+import {
|
|
|
+ appendMessage,
|
|
|
+ prependMessages,
|
|
|
+ editMessage,
|
|
|
+ deleteMessage,
|
|
|
+ confirmMessage,
|
|
|
+} from '../../../../../frontend/js/features/chat/utils/message-list-utils'
|
|
|
+import { User, UserId } from '@ol-types/user'
|
|
|
+import {
|
|
|
+ Message,
|
|
|
+ ServerMessageEntry,
|
|
|
+} from '@/features/chat/context/chat-context'
|
|
|
+
|
|
|
+const testUser: User = {
|
|
|
+ id: '123abc' as UserId,
|
|
|
+ email: 'test-user@example.com',
|
|
|
+}
|
|
|
+
|
|
|
+const otherUser: User = {
|
|
|
+ id: '234other' as UserId,
|
|
|
+ email: 'other-user@example.com',
|
|
|
+}
|
|
|
+
|
|
|
+function createTestMessageList(): Message[] {
|
|
|
+ return [
|
|
|
+ {
|
|
|
+ id: 'msg_1',
|
|
|
+ content: 'hello world',
|
|
|
+ timestamp: new Date().getTime(),
|
|
|
+ user: otherUser,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: 'msg_2',
|
|
|
+ content: 'foo',
|
|
|
+ timestamp: new Date().getTime(),
|
|
|
+ user: testUser,
|
|
|
+ },
|
|
|
+ ]
|
|
|
+}
|
|
|
+describe('message-list-utils', function () {
|
|
|
+ describe('prependMessages()', function () {
|
|
|
+ function createTestMessages(): ServerMessageEntry[] {
|
|
|
+ const message1 = {
|
|
|
+ id: 'prepended_message',
|
|
|
+ content: 'hello',
|
|
|
+ timestamp: new Date().getTime(),
|
|
|
+ user: testUser,
|
|
|
+ }
|
|
|
+ const message2 = { ...message1, id: 'prepended_message_2' }
|
|
|
+ return [message1, message2]
|
|
|
+ }
|
|
|
+
|
|
|
+ it('to an empty list', function () {
|
|
|
+ const messages = createTestMessages()
|
|
|
+ const uniqueMessageIds: string[] = []
|
|
|
+
|
|
|
+ expect(
|
|
|
+ prependMessages([], messages, uniqueMessageIds).messages
|
|
|
+ ).to.deep.equal([
|
|
|
+ {
|
|
|
+ id: messages[0].id,
|
|
|
+ timestamp: messages[0].timestamp,
|
|
|
+ user: messages[0].user,
|
|
|
+ content: messages[0].content,
|
|
|
+ edited: false,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: messages[1].id,
|
|
|
+ timestamp: messages[1].timestamp,
|
|
|
+ user: messages[1].user,
|
|
|
+ content: messages[1].content,
|
|
|
+ edited: false,
|
|
|
+ },
|
|
|
+ ])
|
|
|
+ })
|
|
|
+
|
|
|
+ describe('when the messages to prepend are from the same user', function () {
|
|
|
+ let list, messages: ServerMessageEntry[], uniqueMessageIds: string[]
|
|
|
+
|
|
|
+ beforeEach(function () {
|
|
|
+ list = createTestMessageList()
|
|
|
+ messages = createTestMessages()
|
|
|
+ messages[0].user = testUser // makes all the messages have the same author
|
|
|
+ uniqueMessageIds = []
|
|
|
+ })
|
|
|
+
|
|
|
+ it('when the prepended messages are close in time, contents should be merged into the same message', function () {
|
|
|
+ const result = prependMessages(
|
|
|
+ createTestMessageList(),
|
|
|
+ messages,
|
|
|
+ uniqueMessageIds
|
|
|
+ ).messages
|
|
|
+ expect(result.length).to.equal(list.length + 2)
|
|
|
+ expect(result[0]).to.deep.equal({
|
|
|
+ id: messages[0].id,
|
|
|
+ timestamp: messages[0].timestamp,
|
|
|
+ user: messages[0].user,
|
|
|
+ content: messages[0].content,
|
|
|
+ edited: false,
|
|
|
+ })
|
|
|
+ expect(result[1]).to.deep.equal({
|
|
|
+ id: messages[1].id,
|
|
|
+ timestamp: messages[1].timestamp,
|
|
|
+ user: messages[1].user,
|
|
|
+ content: messages[1].content,
|
|
|
+ edited: false,
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ it('when the prepended messages are separated in time, each message is prepended', function () {
|
|
|
+ messages[0].timestamp = messages[1].timestamp - 6 * 60 * 1000 // 6 minutes before the next message
|
|
|
+ const result = prependMessages(
|
|
|
+ createTestMessageList(),
|
|
|
+ messages,
|
|
|
+ uniqueMessageIds
|
|
|
+ ).messages
|
|
|
+ expect(result.length).to.equal(list.length + 2)
|
|
|
+ expect(result[0]).to.deep.equal({
|
|
|
+ id: messages[0].id,
|
|
|
+ timestamp: messages[0].timestamp,
|
|
|
+ user: messages[0].user,
|
|
|
+ content: messages[0].content,
|
|
|
+ edited: false,
|
|
|
+ })
|
|
|
+ expect(result[1]).to.deep.equal({
|
|
|
+ id: messages[1].id,
|
|
|
+ timestamp: messages[1].timestamp,
|
|
|
+ user: messages[1].user,
|
|
|
+ content: messages[1].content,
|
|
|
+ edited: false,
|
|
|
+ })
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ describe('when the messages to prepend are from different users', function () {
|
|
|
+ let list, messages: ServerMessageEntry[], uniqueMessageIds: string[]
|
|
|
+
|
|
|
+ beforeEach(function () {
|
|
|
+ list = createTestMessageList()
|
|
|
+ messages = createTestMessages()
|
|
|
+ uniqueMessageIds = []
|
|
|
+ })
|
|
|
+
|
|
|
+ it('should prepend separate messages to the list', function () {
|
|
|
+ messages[0].user = otherUser
|
|
|
+ const result = prependMessages(
|
|
|
+ createTestMessageList(),
|
|
|
+ messages,
|
|
|
+ uniqueMessageIds
|
|
|
+ ).messages
|
|
|
+ expect(result.length).to.equal(list.length + 2)
|
|
|
+ expect(result[0]).to.deep.equal({
|
|
|
+ id: messages[0].id,
|
|
|
+ timestamp: messages[0].timestamp,
|
|
|
+ user: messages[0].user,
|
|
|
+ content: messages[0].content,
|
|
|
+ edited: false,
|
|
|
+ })
|
|
|
+ expect(result[1]).to.deep.equal({
|
|
|
+ id: messages[1].id,
|
|
|
+ timestamp: messages[1].timestamp,
|
|
|
+ user: messages[1].user,
|
|
|
+ content: messages[1].content,
|
|
|
+ edited: false,
|
|
|
+ })
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ it('should merge the prepended messages into the first existing one when user is same user and are close in time', function () {
|
|
|
+ const list = createTestMessageList()
|
|
|
+ const messages = createTestMessages()
|
|
|
+ messages[0].user = messages[1].user = list[0].user
|
|
|
+ const uniqueMessageIds: string[] = []
|
|
|
+
|
|
|
+ const result = prependMessages(
|
|
|
+ createTestMessageList(),
|
|
|
+ messages,
|
|
|
+ uniqueMessageIds
|
|
|
+ ).messages
|
|
|
+ expect(result.length).to.equal(list.length + 2)
|
|
|
+ expect(result[0]).to.deep.equal({
|
|
|
+ id: messages[0].id,
|
|
|
+ timestamp: messages[0].timestamp,
|
|
|
+ user: messages[0].user,
|
|
|
+ content: messages[0].content,
|
|
|
+ edited: false,
|
|
|
+ })
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ describe('appendMessage()', function () {
|
|
|
+ function createTestMessage() {
|
|
|
+ return {
|
|
|
+ id: 'appended_message',
|
|
|
+ content: 'hi!',
|
|
|
+ timestamp: new Date().getTime(),
|
|
|
+ user: testUser,
|
|
|
+ pending: false,
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ it('to an empty list', function () {
|
|
|
+ const testMessage = createTestMessage()
|
|
|
+ const uniqueMessageIds: string[] = []
|
|
|
+
|
|
|
+ expect(
|
|
|
+ appendMessage([], testMessage, uniqueMessageIds).messages
|
|
|
+ ).to.deep.equal([
|
|
|
+ {
|
|
|
+ id: 'appended_message',
|
|
|
+ timestamp: testMessage.timestamp,
|
|
|
+ user: testMessage.user,
|
|
|
+ content: testMessage.content,
|
|
|
+ pending: false,
|
|
|
+ edited: false,
|
|
|
+ },
|
|
|
+ ])
|
|
|
+ })
|
|
|
+
|
|
|
+ describe('messages appended shortly after the last message on the list', function () {
|
|
|
+ let list: Message[],
|
|
|
+ message: ServerMessageEntry,
|
|
|
+ uniqueMessageIds: string[]
|
|
|
+
|
|
|
+ beforeEach(function () {
|
|
|
+ list = createTestMessageList()
|
|
|
+ message = createTestMessage()
|
|
|
+ message.timestamp = list[1].timestamp + 6 * 1000 // 6 seconds after the last message in the list
|
|
|
+ uniqueMessageIds = []
|
|
|
+ })
|
|
|
+
|
|
|
+ describe('when the author is the same as the last message', function () {
|
|
|
+ it('should append the content to the last message', function () {
|
|
|
+ const result = appendMessage(list, message, uniqueMessageIds).messages
|
|
|
+ expect(result.length).to.equal(list.length + 1)
|
|
|
+ expect(result[2]).to.deep.equal({
|
|
|
+ id: message.id,
|
|
|
+ timestamp: message.timestamp,
|
|
|
+ user: message.user,
|
|
|
+ content: message.content,
|
|
|
+ pending: false,
|
|
|
+ edited: false,
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ it('should update the last message timestamp', function () {
|
|
|
+ const result = appendMessage(list, message, uniqueMessageIds).messages
|
|
|
+ expect(result[2].timestamp).to.equal(message.timestamp)
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ describe('when the author is different than the last message', function () {
|
|
|
+ beforeEach(function () {
|
|
|
+ message.user = otherUser
|
|
|
+ })
|
|
|
+
|
|
|
+ it('should append the new message to the list', function () {
|
|
|
+ const result = appendMessage(list, message, uniqueMessageIds).messages
|
|
|
+ expect(result.length).to.equal(list.length + 1)
|
|
|
+ expect(result[2]).to.deep.equal({
|
|
|
+ id: 'appended_message',
|
|
|
+ timestamp: message.timestamp,
|
|
|
+ user: message.user,
|
|
|
+ content: message.content,
|
|
|
+ pending: false,
|
|
|
+ edited: false,
|
|
|
+ })
|
|
|
+ })
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ describe('messages appended later after the last message on the list', function () {
|
|
|
+ let list: Message[],
|
|
|
+ message: ServerMessageEntry,
|
|
|
+ uniqueMessageIds: string[]
|
|
|
+
|
|
|
+ beforeEach(function () {
|
|
|
+ list = createTestMessageList()
|
|
|
+ message = createTestMessage()
|
|
|
+ message.timestamp = list[1].timestamp + 6 * 60 * 1000 // 6 minutes after the last message in the list
|
|
|
+ uniqueMessageIds = []
|
|
|
+ })
|
|
|
+
|
|
|
+ it('when the author is the same as the last message, should be appended as new message', function () {
|
|
|
+ const result = appendMessage(list, message, uniqueMessageIds).messages
|
|
|
+ expect(result.length).to.equal(3)
|
|
|
+ expect(result[2]).to.deep.equal({
|
|
|
+ id: 'appended_message',
|
|
|
+ timestamp: message.timestamp,
|
|
|
+ user: message.user,
|
|
|
+ content: message.content,
|
|
|
+ pending: false,
|
|
|
+ edited: false,
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ it('when the author is the different than the last message, should be appended as new message', function () {
|
|
|
+ message.user = otherUser
|
|
|
+
|
|
|
+ const result = appendMessage(list, message, uniqueMessageIds).messages
|
|
|
+ expect(result.length).to.equal(3)
|
|
|
+ expect(result[2]).to.deep.equal({
|
|
|
+ id: 'appended_message',
|
|
|
+ timestamp: message.timestamp,
|
|
|
+ user: message.user,
|
|
|
+ content: message.content,
|
|
|
+ pending: false,
|
|
|
+ edited: false,
|
|
|
+ })
|
|
|
+ })
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ describe('editMessage()', function () {
|
|
|
+ it('should edit an existing message', function () {
|
|
|
+ const list = createTestMessageList()
|
|
|
+ const messageId = 'msg_1'
|
|
|
+ const newContent = 'edited content'
|
|
|
+
|
|
|
+ const result = editMessage(messageId, newContent, list)
|
|
|
+
|
|
|
+ expect(result.messages.length).to.equal(list.length)
|
|
|
+ expect(result.messages[0]).to.deep.equal({
|
|
|
+ id: messageId,
|
|
|
+ content: newContent,
|
|
|
+ timestamp: list[0].timestamp,
|
|
|
+ user: list[0].user,
|
|
|
+ edited: true,
|
|
|
+ })
|
|
|
+ expect(result.messages[1]).to.deep.equal(list[1])
|
|
|
+ })
|
|
|
+
|
|
|
+ it('should throw an error if message is not found', function () {
|
|
|
+ const list = createTestMessageList()
|
|
|
+ const nonExistentId = 'non_existent_id'
|
|
|
+ const newContent = 'edited content'
|
|
|
+
|
|
|
+ expect(() => {
|
|
|
+ editMessage(nonExistentId, newContent, list)
|
|
|
+ }).to.throw(`Message with id ${nonExistentId} not found in message list`)
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ describe('deleteMessage()', function () {
|
|
|
+ it('should mark an existing message as deleted', function () {
|
|
|
+ const list = createTestMessageList()
|
|
|
+ const messageId = 'msg_1'
|
|
|
+
|
|
|
+ const result = deleteMessage(messageId, list)
|
|
|
+
|
|
|
+ expect(result.messages.length).to.equal(list.length)
|
|
|
+ expect(result.messages[0]).to.deep.equal({
|
|
|
+ id: messageId,
|
|
|
+ content: list[0].content,
|
|
|
+ timestamp: list[0].timestamp,
|
|
|
+ user: list[0].user,
|
|
|
+ deleted: true,
|
|
|
+ })
|
|
|
+ expect(result.messages[1]).to.deep.equal(list[1])
|
|
|
+ })
|
|
|
+
|
|
|
+ it('should throw an error if message is not found', function () {
|
|
|
+ const list = createTestMessageList()
|
|
|
+ const nonExistentId = 'non_existent_id'
|
|
|
+
|
|
|
+ expect(() => {
|
|
|
+ deleteMessage(nonExistentId, list)
|
|
|
+ }).to.throw(`Message with id ${nonExistentId} not found in message list`)
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ describe('confirmMessage()', function () {
|
|
|
+ function createMessageListWithPendingMessage(): Message[] {
|
|
|
+ return [
|
|
|
+ {
|
|
|
+ id: 'msg_1',
|
|
|
+ content: 'hello world',
|
|
|
+ timestamp: new Date().getTime(),
|
|
|
+ user: otherUser,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: 'temp_id',
|
|
|
+ content: 'pending message',
|
|
|
+ timestamp: new Date().getTime(),
|
|
|
+ user: testUser,
|
|
|
+ pending: true,
|
|
|
+ },
|
|
|
+ ]
|
|
|
+ }
|
|
|
+
|
|
|
+ it('should confirm a pending message and update its ID', function () {
|
|
|
+ const list = createMessageListWithPendingMessage()
|
|
|
+ const updatedMessage: Message = {
|
|
|
+ id: 'server_id',
|
|
|
+ content: 'pending message',
|
|
|
+ timestamp: new Date().getTime() + 1000,
|
|
|
+ user: testUser,
|
|
|
+ }
|
|
|
+
|
|
|
+ const result = confirmMessage(updatedMessage, list)
|
|
|
+
|
|
|
+ expect(result.messages.length).to.equal(list.length)
|
|
|
+ expect(result.messages[0]).to.deep.equal(list[0])
|
|
|
+ expect(result.messages[1]).to.deep.equal({
|
|
|
+ id: 'server_id',
|
|
|
+ content: 'pending message',
|
|
|
+ timestamp: updatedMessage.timestamp,
|
|
|
+ user: testUser,
|
|
|
+ pending: false,
|
|
|
+ })
|
|
|
+ expect(result.uniqueMessageIds).to.deep.equal(['msg_1', 'server_id'])
|
|
|
+ })
|
|
|
+
|
|
|
+ it('should throw an error if pending message is not found', function () {
|
|
|
+ const list = createTestMessageList() // No pending messages
|
|
|
+ const updatedMessage: Message = {
|
|
|
+ id: 'server_id',
|
|
|
+ content: 'non-existent pending message',
|
|
|
+ timestamp: new Date().getTime(),
|
|
|
+ user: testUser,
|
|
|
+ }
|
|
|
+
|
|
|
+ expect(() => {
|
|
|
+ confirmMessage(updatedMessage, list)
|
|
|
+ }).to.throw("Couldn't find own message in local state")
|
|
|
+ })
|
|
|
+ })
|
|
|
+})
|