string_file_data.test.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. // @ts-check
  2. 'use strict'
  3. const { expect } = require('chai')
  4. const _ = require('lodash')
  5. const ot = require('..')
  6. const Range = require('../lib/range')
  7. const StringFileData = require('../lib/file_data/string_file_data')
  8. const TrackedChange = require('../lib/file_data/tracked_change')
  9. const TrackingProps = require('../lib/file_data/tracking_props')
  10. const TextOperation = ot.TextOperation
  11. describe('StringFileData', function () {
  12. it('throws when it contains non BMP chars', function () {
  13. const content = '𝌆𝌆𝌆'
  14. const fileData = new StringFileData(content)
  15. const operation = new TextOperation()
  16. operation.insert('aa')
  17. expect(() => {
  18. fileData.edit(operation)
  19. }).to.throw(TextOperation.ApplyError, /string contains non BMP characters/)
  20. })
  21. it('validates string length when edited', function () {
  22. const longString = _.repeat(
  23. 'a',
  24. TextOperation.MAX_STRING_LENGTH_EXCLUDING_TRACKED_DELETES
  25. )
  26. const fileData = new StringFileData(longString)
  27. expect(fileData.getByteLength()).to.equal(longString.length)
  28. expect(fileData.getStringLength()).to.equal(longString.length)
  29. expect(() => {
  30. fileData.edit(new TextOperation().retain(longString.length).insert('x'))
  31. }).to.throw(TextOperation.TooLongError)
  32. expect(fileData.getByteLength()).to.equal(longString.length)
  33. expect(fileData.getStringLength()).to.equal(longString.length)
  34. fileData.edit(new TextOperation().retain(longString.length - 1).remove(1))
  35. expect(fileData.getByteLength()).to.equal(longString.length - 1)
  36. expect(fileData.getStringLength()).to.equal(longString.length - 1)
  37. })
  38. it('ignores tracked deletes when checking the max string length', function () {
  39. const longString = _.repeat(
  40. 'a',
  41. TextOperation.MAX_STRING_LENGTH_EXCLUDING_TRACKED_DELETES
  42. )
  43. const fileData = new StringFileData(longString)
  44. fileData.trackedChanges.add(
  45. new TrackedChange(
  46. new Range(123, 100),
  47. new TrackingProps('delete', 'some-user', new Date())
  48. )
  49. )
  50. fileData.trackedChanges.add(
  51. new TrackedChange(
  52. new Range(456, 50),
  53. new TrackingProps('insert', 'some-user', new Date())
  54. )
  55. )
  56. // Add text the same length as the tracked delete
  57. fileData.edit(
  58. new TextOperation().retain(longString.length).insert('x'.repeat(100))
  59. )
  60. // Add more text
  61. expect(() => {
  62. fileData.edit(
  63. new TextOperation().retain(longString.length + 100).insert('x')
  64. )
  65. }).to.throw(TextOperation.TooLongError)
  66. })
  67. it('getComments() should return an empty array', function () {
  68. const fileData = new StringFileData('test')
  69. expect(fileData.getComments().toRaw()).to.eql([])
  70. })
  71. it('creates StringFileData with comments', function () {
  72. const fileData = new StringFileData('test', [
  73. {
  74. id: 'comm1',
  75. ranges: [
  76. {
  77. pos: 5,
  78. length: 10,
  79. },
  80. ],
  81. },
  82. {
  83. id: 'comm2',
  84. ranges: [
  85. {
  86. pos: 20,
  87. length: 5,
  88. },
  89. ],
  90. },
  91. ])
  92. expect(fileData.getComments().toRaw()).to.eql([
  93. { id: 'comm1', ranges: [{ pos: 5, length: 10 }] },
  94. { id: 'comm2', ranges: [{ pos: 20, length: 5 }] },
  95. ])
  96. })
  97. it('fromRaw() should create StringFileData with comments', function () {
  98. const fileData = StringFileData.fromRaw({
  99. content: 'test',
  100. comments: [
  101. {
  102. id: 'comm1',
  103. ranges: [
  104. {
  105. pos: 5,
  106. length: 10,
  107. },
  108. ],
  109. },
  110. {
  111. id: 'comm2',
  112. ranges: [
  113. {
  114. pos: 20,
  115. length: 5,
  116. },
  117. ],
  118. resolved: true,
  119. },
  120. ],
  121. })
  122. expect(fileData.getComments().toRaw()).to.eql([
  123. { id: 'comm1', ranges: [{ pos: 5, length: 10 }] },
  124. { id: 'comm2', ranges: [{ pos: 20, length: 5 }], resolved: true },
  125. ])
  126. })
  127. it('getContent should filter out tracked deletions when passed option', function () {
  128. const fileData = new StringFileData(
  129. 'the quick brown fox jumps over the lazy dog',
  130. undefined,
  131. [
  132. {
  133. range: { pos: 4, length: 6 },
  134. tracking: {
  135. type: 'delete',
  136. ts: '2024-01-01T00:00:00.000Z',
  137. userId: 'user1',
  138. },
  139. },
  140. {
  141. range: { pos: 35, length: 5 },
  142. tracking: {
  143. type: 'delete',
  144. ts: '2023-01-01T00:00:00.000Z',
  145. userId: 'user2',
  146. },
  147. },
  148. ]
  149. )
  150. expect(fileData.getContent()).to.equal(
  151. 'the quick brown fox jumps over the lazy dog'
  152. )
  153. expect(fileData.getContent({ filterTrackedDeletes: true })).to.equal(
  154. 'the brown fox jumps over the dog'
  155. )
  156. })
  157. it('getContent should keep tracked insertions when passed option to remove tracked changes', function () {
  158. const fileData = new StringFileData(
  159. 'the quick brown fox jumps over the lazy dog',
  160. undefined,
  161. [
  162. {
  163. range: { pos: 4, length: 6 },
  164. tracking: {
  165. type: 'insert',
  166. ts: '2024-01-01T00:00:00.000Z',
  167. userId: 'user1',
  168. },
  169. },
  170. {
  171. range: { pos: 35, length: 5 },
  172. tracking: {
  173. type: 'delete',
  174. ts: '2023-01-01T00:00:00.000Z',
  175. userId: 'user2',
  176. },
  177. },
  178. ]
  179. )
  180. expect(fileData.getContent()).to.equal(
  181. 'the quick brown fox jumps over the lazy dog'
  182. )
  183. expect(fileData.getContent({ filterTrackedDeletes: true })).to.equal(
  184. 'the quick brown fox jumps over the dog'
  185. )
  186. })
  187. })