ranges-tracker-test.js 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. const { expect } = require('chai')
  2. const RangesTracker = require('../..')
  3. describe('RangesTracker', function () {
  4. describe('with duplicate change ids', function () {
  5. beforeEach(function () {
  6. this.comments = []
  7. this.changes = [
  8. { id: 'id1', op: { p: 1, i: 'hello' } },
  9. { id: 'id2', op: { p: 10, i: 'world' } },
  10. { id: 'id3', op: { p: 20, i: '!!!' } },
  11. { id: 'id1', op: { p: 30, d: 'duplicate' } },
  12. ]
  13. this.rangesTracker = new RangesTracker(this.changes, this.comments)
  14. })
  15. it('getChanges() returns all changes with the given ids', function () {
  16. expect(this.rangesTracker.getChanges(['id1', 'id2'])).to.deep.equal([
  17. this.changes[0],
  18. this.changes[1],
  19. this.changes[3],
  20. ])
  21. })
  22. it('removeChangeIds() removes all changes with the given ids', function () {
  23. this.rangesTracker.removeChangeIds(['id1', 'id2'])
  24. expect(this.rangesTracker.changes).to.deep.equal([this.changes[2]])
  25. })
  26. })
  27. describe('with duplicate tracked insert ids', function () {
  28. beforeEach(function () {
  29. this.comments = []
  30. this.changes = [
  31. { id: 'id1', op: { p: 10, i: 'one' } },
  32. { id: 'id1', op: { p: 20, i: 'two' } },
  33. { id: 'id1', op: { p: 30, d: 'three' } },
  34. ]
  35. this.rangesTracker = new RangesTracker(this.changes, this.comments)
  36. })
  37. it("deleting one tracked insert doesn't delete the others", function () {
  38. this.rangesTracker.applyOp({ p: 20, d: 'two', fixedRemoveChange: true })
  39. expect(this.rangesTracker.changes).to.deep.equal([
  40. this.changes[0],
  41. this.changes[2],
  42. ])
  43. })
  44. })
  45. describe('with duplicate tracked delete ids', function () {
  46. beforeEach(function () {
  47. this.comments = []
  48. this.changes = [
  49. { id: 'id1', op: { p: 10, d: 'one' } },
  50. { id: 'id1', op: { p: 20, d: 'two' } },
  51. { id: 'id1', op: { p: 30, d: 'three' } },
  52. ]
  53. this.rangesTracker = new RangesTracker(this.changes, this.comments)
  54. })
  55. it('deleting over tracked deletes in tracked changes mode removes the tracked deletes covered', function () {
  56. this.rangesTracker.track_changes = true
  57. this.rangesTracker.applyOp({
  58. p: 15,
  59. d: '567890123456789012345',
  60. fixedRemoveChange: true,
  61. })
  62. expect(this.rangesTracker.changes.map(c => c.op)).to.deep.equal([
  63. { p: 10, d: 'one' },
  64. { p: 15, d: '56789two0123456789three012345' },
  65. ])
  66. })
  67. it('a tracked delete between two tracked deletes joins them into a single tracked delete', function () {
  68. this.rangesTracker.track_changes = true
  69. this.rangesTracker.applyOp({
  70. p: 20,
  71. d: '0123456789',
  72. fixedRemoveChange: true,
  73. })
  74. expect(this.rangesTracker.changes.map(c => c.op)).to.deep.equal([
  75. { p: 10, d: 'one' },
  76. { p: 20, d: 'two0123456789three' },
  77. ])
  78. })
  79. it("rejecting one tracked delete doesn't reject the others", function () {
  80. this.rangesTracker.track_changes = true
  81. this.rangesTracker.applyOp({
  82. p: 20,
  83. i: 'two',
  84. u: true,
  85. fixedRemoveChange: true,
  86. })
  87. expect(this.rangesTracker.changes.map(c => c.op)).to.deep.equal([
  88. { p: 10, d: 'one' },
  89. { p: 33, d: 'three' },
  90. ])
  91. })
  92. it("rejecting all tracked deletes doesn't introduce tracked inserts", function () {
  93. this.rangesTracker.track_changes = true
  94. this.rangesTracker.applyOp({
  95. p: 10,
  96. i: 'one',
  97. u: true,
  98. fixedRemoveChange: true,
  99. })
  100. this.rangesTracker.applyOp({
  101. p: 23,
  102. i: 'two',
  103. u: true,
  104. fixedRemoveChange: true,
  105. })
  106. this.rangesTracker.applyOp({
  107. p: 36,
  108. i: 'three',
  109. u: true,
  110. fixedRemoveChange: true,
  111. })
  112. expect(this.rangesTracker.changes.map(c => c.op)).to.deep.equal([])
  113. })
  114. })
  115. describe('with multiple tracked deletes at the same position', function () {
  116. beforeEach(function () {
  117. this.comments = []
  118. this.changes = [
  119. { id: 'id1', op: { p: 33, d: 'before' } },
  120. { id: 'id2', op: { p: 50, d: 'right before' } },
  121. { id: 'id3', op: { p: 50, d: 'this one' } },
  122. { id: 'id4', op: { p: 50, d: 'right after' } },
  123. { id: 'id5', op: { p: 75, d: 'long after' } },
  124. ]
  125. this.rangesTracker = new RangesTracker(this.changes, this.comments)
  126. })
  127. describe('with the orderedRejections flag', function () {
  128. it('preserves the text order when rejecting changes', function () {
  129. this.rangesTracker.applyOp(
  130. { p: 50, i: 'this one', u: true, orderedRejections: true },
  131. { user_id: 'user-id' }
  132. )
  133. expect(this.rangesTracker.changes).to.deep.equal([
  134. { id: 'id1', op: { p: 33, d: 'before' } },
  135. { id: 'id2', op: { p: 50, d: 'right before' } },
  136. { id: 'id4', op: { p: 58, d: 'right after' } },
  137. { id: 'id5', op: { p: 83, d: 'long after' } },
  138. ])
  139. })
  140. it('moves all tracked deletes after the insert if not rejecting changes', function () {
  141. this.rangesTracker.applyOp(
  142. { p: 50, i: 'some other text', u: true, orderedRejections: true },
  143. { user_id: 'user-id' }
  144. )
  145. expect(this.rangesTracker.changes).to.deep.equal([
  146. { id: 'id1', op: { p: 33, d: 'before' } },
  147. { id: 'id2', op: { p: 65, d: 'right before' } },
  148. { id: 'id3', op: { p: 65, d: 'this one' } },
  149. { id: 'id4', op: { p: 65, d: 'right after' } },
  150. { id: 'id5', op: { p: 90, d: 'long after' } },
  151. ])
  152. })
  153. })
  154. describe('without the orderedRejections flag', function () {
  155. it('puts the insert before tracked deletes when rejecting changes', function () {
  156. this.rangesTracker.applyOp(
  157. { p: 50, i: 'this one', u: true },
  158. { user_id: 'user-id' }
  159. )
  160. expect(this.rangesTracker.changes).to.deep.equal([
  161. { id: 'id1', op: { p: 33, d: 'before' } },
  162. { id: 'id2', op: { p: 58, d: 'right before' } },
  163. { id: 'id4', op: { p: 58, d: 'right after' } },
  164. { id: 'id5', op: { p: 83, d: 'long after' } },
  165. ])
  166. })
  167. it('moves all tracked deletes after the insert if not rejecting changes', function () {
  168. this.rangesTracker.applyOp(
  169. { p: 50, i: 'some other text', u: true },
  170. { user_id: 'user-id' }
  171. )
  172. expect(this.rangesTracker.changes).to.deep.equal([
  173. { id: 'id1', op: { p: 33, d: 'before' } },
  174. { id: 'id2', op: { p: 65, d: 'right before' } },
  175. { id: 'id3', op: { p: 65, d: 'this one' } },
  176. { id: 'id4', op: { p: 65, d: 'right after' } },
  177. { id: 'id5', op: { p: 90, d: 'long after' } },
  178. ])
  179. })
  180. })
  181. })
  182. describe('with multiple tracked deletes at the same position with the same content', function () {
  183. beforeEach(function () {
  184. this.comments = []
  185. this.changes = [
  186. { id: 'id1', op: { p: 10, d: 'cat' } },
  187. { id: 'id2', op: { p: 10, d: 'giraffe' } },
  188. { id: 'id3', op: { p: 10, d: 'cat' } },
  189. { id: 'id4', op: { p: 10, d: 'giraffe' } },
  190. ]
  191. this.rangesTracker = new RangesTracker(this.changes, this.comments)
  192. })
  193. describe('with the orderedRejections flag', function () {
  194. it('removes only the first matching tracked delete', function () {
  195. this.rangesTracker.applyOp(
  196. { p: 10, i: 'giraffe', u: true, orderedRejections: true },
  197. { user_id: 'user-id' }
  198. )
  199. expect(this.rangesTracker.changes).to.deep.equal([
  200. { id: 'id1', op: { p: 10, d: 'cat' } },
  201. { id: 'id3', op: { p: 17, d: 'cat' } },
  202. { id: 'id4', op: { p: 17, d: 'giraffe' } },
  203. ])
  204. })
  205. })
  206. describe('without the orderedRejections flag', function () {
  207. it('removes all matching tracked delete', function () {
  208. this.rangesTracker.applyOp(
  209. { p: 10, i: 'giraffe', u: true },
  210. { user_id: 'user-id' }
  211. )
  212. expect(this.rangesTracker.changes).to.deep.equal([
  213. { id: 'id1', op: { p: 17, d: 'cat' } },
  214. { id: 'id3', op: { p: 17, d: 'cat' } },
  215. ])
  216. })
  217. })
  218. })
  219. describe('with a tracked insert at the same position as a tracked delete', function () {
  220. beforeEach(function () {
  221. this.comments = []
  222. this.changes = [
  223. {
  224. id: 'id1',
  225. op: { p: 5, d: 'before' },
  226. metadata: { user_id: 'user-id' },
  227. },
  228. {
  229. id: 'id2',
  230. op: { p: 10, d: 'delete' },
  231. metadata: { user_id: 'user-id' },
  232. },
  233. {
  234. id: 'id3',
  235. op: { p: 10, i: 'insert' },
  236. metadata: { user_id: 'user-id' },
  237. },
  238. ]
  239. this.rangesTracker = new RangesTracker(this.changes, this.comments)
  240. })
  241. describe('with the orderedRejections flag', function () {
  242. it('places a tracked insert at the same position before both the delete and the insert', function () {
  243. this.rangesTracker.track_changes = true
  244. this.rangesTracker.applyOp(
  245. { p: 10, i: 'incoming', orderedRejections: true },
  246. { user_id: 'user-id' }
  247. )
  248. expect(
  249. this.rangesTracker.changes.map(change => change.op)
  250. ).to.deep.equal([
  251. { p: 5, d: 'before' },
  252. { p: 10, i: 'incoming' },
  253. { p: 18, d: 'delete' },
  254. { p: 18, i: 'insert' },
  255. ])
  256. })
  257. })
  258. describe('without the orderedRejections flag', function () {
  259. it('places a tracked insert at the same position before both the delete and the insert', function () {
  260. this.rangesTracker.track_changes = true
  261. this.rangesTracker.applyOp(
  262. { p: 10, i: 'incoming' },
  263. { user_id: 'user-id' }
  264. )
  265. expect(
  266. this.rangesTracker.changes.map(change => change.op)
  267. ).to.deep.equal([
  268. { p: 5, d: 'before' },
  269. { p: 10, i: 'incoming' },
  270. { p: 18, d: 'delete' },
  271. { p: 18, i: 'insert' },
  272. ])
  273. })
  274. })
  275. })
  276. })