RangeManager.test.js 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. import path from 'node:path'
  2. import { beforeEach, describe, expect, it, vi } from 'vitest'
  3. import { ObjectId } from 'mongodb-legacy'
  4. const modulePath = path.join(
  5. import.meta.dirname,
  6. '../../../app/js/RangeManager'
  7. )
  8. describe('RangeManager', () => {
  9. beforeEach(async ctx => {
  10. vi.doMock('../../../app/js/mongodb', () => ({
  11. default: {
  12. ObjectId,
  13. },
  14. }))
  15. ctx.RangeManager = (await import(modulePath)).default
  16. })
  17. describe('jsonRangesToMongo', () => {
  18. it('should convert ObjectIds and dates to proper objects and fix comment id', ctx => {
  19. const changeId = new ObjectId().toString()
  20. const commentId = new ObjectId().toString()
  21. const userId = new ObjectId().toString()
  22. const threadId = new ObjectId().toString()
  23. const ts = new Date().toJSON()
  24. ctx.RangeManager.jsonRangesToMongo({
  25. changes: [
  26. {
  27. id: changeId,
  28. op: { i: 'foo', p: 3 },
  29. metadata: {
  30. user_id: userId,
  31. ts,
  32. },
  33. },
  34. ],
  35. comments: [
  36. {
  37. id: commentId,
  38. op: { c: 'foo', p: 3, t: threadId },
  39. },
  40. ],
  41. }).should.deep.equal({
  42. changes: [
  43. {
  44. id: new ObjectId(changeId),
  45. op: { i: 'foo', p: 3 },
  46. metadata: {
  47. user_id: new ObjectId(userId),
  48. ts: new Date(ts),
  49. },
  50. },
  51. ],
  52. comments: [
  53. {
  54. id: new ObjectId(threadId),
  55. op: { c: 'foo', p: 3, t: new ObjectId(threadId) },
  56. },
  57. ],
  58. })
  59. })
  60. it('should leave malformed ObjectIds as they are', ctx => {
  61. const changeId = 'foo'
  62. const commentId = 'bar'
  63. const userId = 'baz'
  64. ctx.RangeManager.jsonRangesToMongo({
  65. changes: [
  66. {
  67. id: changeId,
  68. metadata: {
  69. user_id: userId,
  70. },
  71. },
  72. ],
  73. comments: [
  74. {
  75. id: commentId,
  76. },
  77. ],
  78. }).should.deep.equal({
  79. changes: [
  80. {
  81. id: changeId,
  82. metadata: {
  83. user_id: userId,
  84. },
  85. },
  86. ],
  87. comments: [
  88. {
  89. id: commentId,
  90. },
  91. ],
  92. })
  93. })
  94. it('should be consistent when transformed through json -> mongo -> json', ctx => {
  95. const changeId = new ObjectId().toString()
  96. const userId = new ObjectId().toString()
  97. const threadId = new ObjectId().toString()
  98. const ts = new Date().toJSON()
  99. const ranges1 = {
  100. changes: [
  101. {
  102. id: changeId,
  103. op: { i: 'foo', p: 3 },
  104. metadata: {
  105. user_id: userId,
  106. ts,
  107. },
  108. },
  109. ],
  110. comments: [
  111. {
  112. id: threadId,
  113. op: { c: 'foo', p: 3, t: threadId },
  114. },
  115. ],
  116. }
  117. const ranges1Copy = JSON.parse(JSON.stringify(ranges1)) // jsonRangesToMongo modifies in place
  118. const ranges2 = JSON.parse(
  119. JSON.stringify(ctx.RangeManager.jsonRangesToMongo(ranges1Copy))
  120. )
  121. ranges1.should.deep.equal(ranges2)
  122. })
  123. })
  124. return describe('shouldUpdateRanges', () => {
  125. beforeEach(ctx => {
  126. const threadId = new ObjectId()
  127. ctx.ranges = {
  128. changes: [
  129. {
  130. id: new ObjectId(),
  131. op: { i: 'foo', p: 3 },
  132. metadata: {
  133. user_id: new ObjectId(),
  134. ts: new Date(),
  135. },
  136. },
  137. ],
  138. comments: [
  139. {
  140. id: threadId,
  141. op: { c: 'foo', p: 3, t: threadId },
  142. },
  143. ],
  144. }
  145. ctx.ranges_copy = ctx.RangeManager.jsonRangesToMongo(
  146. JSON.parse(JSON.stringify(ctx.ranges))
  147. )
  148. })
  149. describe('with a blank new range', () => {
  150. it('should throw an error', ctx => {
  151. expect(() => {
  152. ctx.RangeManager.shouldUpdateRanges(ctx.ranges, null)
  153. }).to.throw(Error)
  154. })
  155. })
  156. describe('with a blank old range', () => {
  157. it('should treat it like {}', ctx => {
  158. ctx.RangeManager.shouldUpdateRanges(null, {}).should.equal(false)
  159. ctx.RangeManager.shouldUpdateRanges(null, ctx.ranges).should.equal(true)
  160. })
  161. })
  162. describe('with no changes', () => {
  163. it('should return false', ctx => {
  164. ctx.RangeManager.shouldUpdateRanges(
  165. ctx.ranges,
  166. ctx.ranges_copy
  167. ).should.equal(false)
  168. })
  169. })
  170. describe('with changes', () => {
  171. it('should return true when the change id changes', ctx => {
  172. ctx.ranges_copy.changes[0].id = new ObjectId()
  173. ctx.RangeManager.shouldUpdateRanges(
  174. ctx.ranges,
  175. ctx.ranges_copy
  176. ).should.equal(true)
  177. })
  178. it('should return true when the change user id changes', ctx => {
  179. ctx.ranges_copy.changes[0].metadata.user_id = new ObjectId()
  180. ctx.RangeManager.shouldUpdateRanges(
  181. ctx.ranges,
  182. ctx.ranges_copy
  183. ).should.equal(true)
  184. })
  185. it('should return true when the change ts changes', ctx => {
  186. ctx.ranges_copy.changes[0].metadata.ts = new Date(Date.now() + 1000)
  187. ctx.RangeManager.shouldUpdateRanges(
  188. ctx.ranges,
  189. ctx.ranges_copy
  190. ).should.equal(true)
  191. })
  192. it('should return true when the change op changes', ctx => {
  193. ctx.ranges_copy.changes[0].op.i = 'bar'
  194. ctx.RangeManager.shouldUpdateRanges(
  195. ctx.ranges,
  196. ctx.ranges_copy
  197. ).should.equal(true)
  198. })
  199. it('should return true when the comment id changes', ctx => {
  200. ctx.ranges_copy.comments[0].id = new ObjectId()
  201. ctx.RangeManager.shouldUpdateRanges(
  202. ctx.ranges,
  203. ctx.ranges_copy
  204. ).should.equal(true)
  205. })
  206. it('should return true when the comment offset changes', ctx => {
  207. ctx.ranges_copy.comments[0].op.p = 17
  208. ctx.RangeManager.shouldUpdateRanges(
  209. ctx.ranges,
  210. ctx.ranges_copy
  211. ).should.equal(true)
  212. })
  213. it('should return true when the comment content changes', ctx => {
  214. ctx.ranges_copy.comments[0].op.c = 'bar'
  215. ctx.RangeManager.shouldUpdateRanges(
  216. ctx.ranges,
  217. ctx.ranges_copy
  218. ).should.equal(true)
  219. })
  220. })
  221. })
  222. })