message-list-utils.test.tsx 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  1. import { expect } from 'chai'
  2. import {
  3. appendMessage,
  4. prependMessages,
  5. editMessage,
  6. deleteMessage,
  7. confirmMessage,
  8. } from '../../../../../frontend/js/features/chat/utils/message-list-utils'
  9. import { User, UserId } from '@ol-types/user'
  10. import {
  11. Message,
  12. ServerMessageEntry,
  13. } from '@/features/chat/context/chat-context'
  14. const testUser: User = {
  15. id: '123abc' as UserId,
  16. email: 'test-user@example.com',
  17. }
  18. const otherUser: User = {
  19. id: '234other' as UserId,
  20. email: 'other-user@example.com',
  21. }
  22. function createTestMessageList(): Message[] {
  23. return [
  24. {
  25. id: 'msg_1',
  26. content: 'hello world',
  27. timestamp: new Date().getTime(),
  28. user: otherUser,
  29. },
  30. {
  31. id: 'msg_2',
  32. content: 'foo',
  33. timestamp: new Date().getTime(),
  34. user: testUser,
  35. },
  36. ]
  37. }
  38. describe('message-list-utils', function () {
  39. describe('prependMessages()', function () {
  40. function createTestMessages(): ServerMessageEntry[] {
  41. const message1 = {
  42. id: 'prepended_message',
  43. content: 'hello',
  44. timestamp: new Date().getTime(),
  45. user: testUser,
  46. }
  47. const message2 = { ...message1, id: 'prepended_message_2' }
  48. return [message1, message2]
  49. }
  50. it('to an empty list', function () {
  51. const messages = createTestMessages()
  52. const uniqueMessageIds: string[] = []
  53. expect(
  54. prependMessages([], messages, uniqueMessageIds).messages
  55. ).to.deep.equal([
  56. {
  57. id: messages[0].id,
  58. timestamp: messages[0].timestamp,
  59. user: messages[0].user,
  60. content: messages[0].content,
  61. edited: false,
  62. },
  63. {
  64. id: messages[1].id,
  65. timestamp: messages[1].timestamp,
  66. user: messages[1].user,
  67. content: messages[1].content,
  68. edited: false,
  69. },
  70. ])
  71. })
  72. describe('when the messages to prepend are from the same user', function () {
  73. let list, messages: ServerMessageEntry[], uniqueMessageIds: string[]
  74. beforeEach(function () {
  75. list = createTestMessageList()
  76. messages = createTestMessages()
  77. messages[0].user = testUser // makes all the messages have the same author
  78. uniqueMessageIds = []
  79. })
  80. it('when the prepended messages are close in time, contents should be merged into the same message', function () {
  81. const result = prependMessages(
  82. createTestMessageList(),
  83. messages,
  84. uniqueMessageIds
  85. ).messages
  86. expect(result.length).to.equal(list.length + 2)
  87. expect(result[0]).to.deep.equal({
  88. id: messages[0].id,
  89. timestamp: messages[0].timestamp,
  90. user: messages[0].user,
  91. content: messages[0].content,
  92. edited: false,
  93. })
  94. expect(result[1]).to.deep.equal({
  95. id: messages[1].id,
  96. timestamp: messages[1].timestamp,
  97. user: messages[1].user,
  98. content: messages[1].content,
  99. edited: false,
  100. })
  101. })
  102. it('when the prepended messages are separated in time, each message is prepended', function () {
  103. messages[0].timestamp = messages[1].timestamp - 6 * 60 * 1000 // 6 minutes before the next message
  104. const result = prependMessages(
  105. createTestMessageList(),
  106. messages,
  107. uniqueMessageIds
  108. ).messages
  109. expect(result.length).to.equal(list.length + 2)
  110. expect(result[0]).to.deep.equal({
  111. id: messages[0].id,
  112. timestamp: messages[0].timestamp,
  113. user: messages[0].user,
  114. content: messages[0].content,
  115. edited: false,
  116. })
  117. expect(result[1]).to.deep.equal({
  118. id: messages[1].id,
  119. timestamp: messages[1].timestamp,
  120. user: messages[1].user,
  121. content: messages[1].content,
  122. edited: false,
  123. })
  124. })
  125. })
  126. describe('when the messages to prepend are from different users', function () {
  127. let list, messages: ServerMessageEntry[], uniqueMessageIds: string[]
  128. beforeEach(function () {
  129. list = createTestMessageList()
  130. messages = createTestMessages()
  131. uniqueMessageIds = []
  132. })
  133. it('should prepend separate messages to the list', function () {
  134. messages[0].user = otherUser
  135. const result = prependMessages(
  136. createTestMessageList(),
  137. messages,
  138. uniqueMessageIds
  139. ).messages
  140. expect(result.length).to.equal(list.length + 2)
  141. expect(result[0]).to.deep.equal({
  142. id: messages[0].id,
  143. timestamp: messages[0].timestamp,
  144. user: messages[0].user,
  145. content: messages[0].content,
  146. edited: false,
  147. })
  148. expect(result[1]).to.deep.equal({
  149. id: messages[1].id,
  150. timestamp: messages[1].timestamp,
  151. user: messages[1].user,
  152. content: messages[1].content,
  153. edited: false,
  154. })
  155. })
  156. })
  157. it('should merge the prepended messages into the first existing one when user is same user and are close in time', function () {
  158. const list = createTestMessageList()
  159. const messages = createTestMessages()
  160. messages[0].user = messages[1].user = list[0].user
  161. const uniqueMessageIds: string[] = []
  162. const result = prependMessages(
  163. createTestMessageList(),
  164. messages,
  165. uniqueMessageIds
  166. ).messages
  167. expect(result.length).to.equal(list.length + 2)
  168. expect(result[0]).to.deep.equal({
  169. id: messages[0].id,
  170. timestamp: messages[0].timestamp,
  171. user: messages[0].user,
  172. content: messages[0].content,
  173. edited: false,
  174. })
  175. })
  176. })
  177. describe('appendMessage()', function () {
  178. function createTestMessage() {
  179. return {
  180. id: 'appended_message',
  181. content: 'hi!',
  182. timestamp: new Date().getTime(),
  183. user: testUser,
  184. pending: false,
  185. }
  186. }
  187. it('to an empty list', function () {
  188. const testMessage = createTestMessage()
  189. const uniqueMessageIds: string[] = []
  190. expect(
  191. appendMessage([], testMessage, uniqueMessageIds).messages
  192. ).to.deep.equal([
  193. {
  194. id: 'appended_message',
  195. timestamp: testMessage.timestamp,
  196. user: testMessage.user,
  197. content: testMessage.content,
  198. pending: false,
  199. edited: false,
  200. },
  201. ])
  202. })
  203. describe('messages appended shortly after the last message on the list', function () {
  204. let list: Message[],
  205. message: ServerMessageEntry,
  206. uniqueMessageIds: string[]
  207. beforeEach(function () {
  208. list = createTestMessageList()
  209. message = createTestMessage()
  210. message.timestamp = list[1].timestamp + 6 * 1000 // 6 seconds after the last message in the list
  211. uniqueMessageIds = []
  212. })
  213. describe('when the author is the same as the last message', function () {
  214. it('should append the content to the last message', function () {
  215. const result = appendMessage(list, message, uniqueMessageIds).messages
  216. expect(result.length).to.equal(list.length + 1)
  217. expect(result[2]).to.deep.equal({
  218. id: message.id,
  219. timestamp: message.timestamp,
  220. user: message.user,
  221. content: message.content,
  222. pending: false,
  223. edited: false,
  224. })
  225. })
  226. it('should update the last message timestamp', function () {
  227. const result = appendMessage(list, message, uniqueMessageIds).messages
  228. expect(result[2].timestamp).to.equal(message.timestamp)
  229. })
  230. })
  231. describe('when the author is different than the last message', function () {
  232. beforeEach(function () {
  233. message.user = otherUser
  234. })
  235. it('should append the new message to the list', function () {
  236. const result = appendMessage(list, message, uniqueMessageIds).messages
  237. expect(result.length).to.equal(list.length + 1)
  238. expect(result[2]).to.deep.equal({
  239. id: 'appended_message',
  240. timestamp: message.timestamp,
  241. user: message.user,
  242. content: message.content,
  243. pending: false,
  244. edited: false,
  245. })
  246. })
  247. })
  248. })
  249. describe('messages appended later after the last message on the list', function () {
  250. let list: Message[],
  251. message: ServerMessageEntry,
  252. uniqueMessageIds: string[]
  253. beforeEach(function () {
  254. list = createTestMessageList()
  255. message = createTestMessage()
  256. message.timestamp = list[1].timestamp + 6 * 60 * 1000 // 6 minutes after the last message in the list
  257. uniqueMessageIds = []
  258. })
  259. it('when the author is the same as the last message, should be appended as new message', function () {
  260. const result = appendMessage(list, message, uniqueMessageIds).messages
  261. expect(result.length).to.equal(3)
  262. expect(result[2]).to.deep.equal({
  263. id: 'appended_message',
  264. timestamp: message.timestamp,
  265. user: message.user,
  266. content: message.content,
  267. pending: false,
  268. edited: false,
  269. })
  270. })
  271. it('when the author is the different than the last message, should be appended as new message', function () {
  272. message.user = otherUser
  273. const result = appendMessage(list, message, uniqueMessageIds).messages
  274. expect(result.length).to.equal(3)
  275. expect(result[2]).to.deep.equal({
  276. id: 'appended_message',
  277. timestamp: message.timestamp,
  278. user: message.user,
  279. content: message.content,
  280. pending: false,
  281. edited: false,
  282. })
  283. })
  284. })
  285. })
  286. describe('editMessage()', function () {
  287. it('should edit an existing message', function () {
  288. const list = createTestMessageList()
  289. const messageId = 'msg_1'
  290. const newContent = 'edited content'
  291. const result = editMessage(messageId, newContent, list)
  292. expect(result.messages.length).to.equal(list.length)
  293. expect(result.messages[0]).to.deep.equal({
  294. id: messageId,
  295. content: newContent,
  296. timestamp: list[0].timestamp,
  297. user: list[0].user,
  298. edited: true,
  299. })
  300. expect(result.messages[1]).to.deep.equal(list[1])
  301. })
  302. it('should throw an error if message is not found', function () {
  303. const list = createTestMessageList()
  304. const nonExistentId = 'non_existent_id'
  305. const newContent = 'edited content'
  306. expect(() => {
  307. editMessage(nonExistentId, newContent, list)
  308. }).to.throw(`Message with id ${nonExistentId} not found in message list`)
  309. })
  310. })
  311. describe('deleteMessage()', function () {
  312. it('should mark an existing message as deleted', function () {
  313. const list = createTestMessageList()
  314. const messageId = 'msg_1'
  315. const result = deleteMessage(messageId, list)
  316. expect(result.messages.length).to.equal(list.length)
  317. expect(result.messages[0]).to.deep.equal({
  318. id: messageId,
  319. content: list[0].content,
  320. timestamp: list[0].timestamp,
  321. user: list[0].user,
  322. deleted: true,
  323. })
  324. expect(result.messages[1]).to.deep.equal(list[1])
  325. })
  326. it('should throw an error if message is not found', function () {
  327. const list = createTestMessageList()
  328. const nonExistentId = 'non_existent_id'
  329. expect(() => {
  330. deleteMessage(nonExistentId, list)
  331. }).to.throw(`Message with id ${nonExistentId} not found in message list`)
  332. })
  333. })
  334. describe('confirmMessage()', function () {
  335. function createMessageListWithPendingMessage(): Message[] {
  336. return [
  337. {
  338. id: 'msg_1',
  339. content: 'hello world',
  340. timestamp: new Date().getTime(),
  341. user: otherUser,
  342. },
  343. {
  344. id: 'temp_id',
  345. content: 'pending message',
  346. timestamp: new Date().getTime(),
  347. user: testUser,
  348. pending: true,
  349. },
  350. ]
  351. }
  352. it('should confirm a pending message and update its ID', function () {
  353. const list = createMessageListWithPendingMessage()
  354. const updatedMessage: Message = {
  355. id: 'server_id',
  356. content: 'pending message',
  357. timestamp: new Date().getTime() + 1000,
  358. user: testUser,
  359. }
  360. const result = confirmMessage(updatedMessage, list)
  361. expect(result.messages.length).to.equal(list.length)
  362. expect(result.messages[0]).to.deep.equal(list[0])
  363. expect(result.messages[1]).to.deep.equal({
  364. id: 'server_id',
  365. content: 'pending message',
  366. timestamp: updatedMessage.timestamp,
  367. user: testUser,
  368. pending: false,
  369. })
  370. expect(result.uniqueMessageIds).to.deep.equal(['msg_1', 'server_id'])
  371. })
  372. it('should throw an error if pending message is not found', function () {
  373. const list = createTestMessageList() // No pending messages
  374. const updatedMessage: Message = {
  375. id: 'server_id',
  376. content: 'non-existent pending message',
  377. timestamp: new Date().getTime(),
  378. user: testUser,
  379. }
  380. expect(() => {
  381. confirmMessage(updatedMessage, list)
  382. }).to.throw("Couldn't find own message in local state")
  383. })
  384. })
  385. })