| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221 |
- import sinon from 'sinon'
- import { expect } from 'chai'
- import { strict as esmock } from 'esmock'
- import Core from 'overleaf-editor-core'
- const MODULE_PATH = '../../../../app/js/UpdateTranslator.js'
- describe('UpdateTranslator', function () {
- beforeEach(async function () {
- this.UpdateTranslator = await esmock(MODULE_PATH, {
- 'overleaf-editor-core': Core,
- })
- this.callback = sinon.stub()
- this.project_id = '59bfd450e3028c4d40a1e9aa'
- this.doc_id = '59bfd450e3028c4d40a1e9ab'
- this.file_id = '59bfd450e3028c4d40a1easd'
- this.user_id = '59bb9051abf6e8682a269b64'
- this.version = 0
- this.timestamp = new Date().toJSON()
- this.mockBlobHash = '12345abc12345abc12345abc12345abc12345abc'
- })
- describe('convertToChanges', function () {
- it('can translate doc additions', function () {
- const updates = [
- {
- update: {
- doc: this.doc_id,
- pathname: '/main.tex',
- docLines: 'a\nb',
- meta: {
- user_id: this.user_id,
- ts: this.timestamp,
- },
- },
- blobHash: this.mockBlobHash,
- },
- ]
- const changes = this.UpdateTranslator.convertToChanges(
- this.project_id,
- updates
- ).map(change => change.toRaw())
- expect(changes).to.deep.equal([
- {
- authors: [],
- operations: [
- {
- pathname: 'main.tex',
- file: {
- hash: this.mockBlobHash,
- },
- },
- ],
- v2Authors: [this.user_id],
- timestamp: this.timestamp,
- },
- ])
- })
- it('can translate file additions', function () {
- const updates = [
- {
- update: {
- file: this.file_id,
- pathname: '/test.png',
- url: 'filestore.example.com/test.png',
- meta: {
- user_id: this.user_id,
- ts: this.timestamp,
- },
- },
- blobHash: this.mockBlobHash,
- },
- ]
- const changes = this.UpdateTranslator.convertToChanges(
- this.project_id,
- updates
- ).map(change => change.toRaw())
- expect(changes).to.deep.equal([
- {
- authors: [],
- operations: [
- {
- pathname: 'test.png',
- file: {
- hash: this.mockBlobHash,
- },
- },
- ],
- v2Authors: [this.user_id],
- timestamp: this.timestamp,
- },
- ])
- })
- it('can translate doc renames', function () {
- const updates = [
- {
- update: {
- doc: this.doc_id,
- pathname: '/main.tex',
- new_pathname: '/new_main.tex',
- meta: {
- user_id: this.user_id,
- ts: this.timestamp,
- },
- },
- },
- ]
- const changes = this.UpdateTranslator.convertToChanges(
- this.project_id,
- updates
- ).map(change => change.toRaw())
- expect(changes).to.deep.equal([
- {
- authors: [],
- operations: [
- {
- pathname: 'main.tex',
- newPathname: 'new_main.tex',
- },
- ],
- v2Authors: [this.user_id],
- timestamp: this.timestamp,
- },
- ])
- })
- it('can translate file renames', function () {
- const updates = [
- {
- update: {
- file: this.file_id,
- pathname: '/test.png',
- new_pathname: '/new_test.png',
- meta: {
- user_id: this.user_id,
- ts: this.timestamp,
- },
- },
- },
- ]
- const changes = this.UpdateTranslator.convertToChanges(
- this.project_id,
- updates
- ).map(change => change.toRaw())
- expect(changes).to.deep.equal([
- {
- authors: [],
- operations: [
- {
- pathname: 'test.png',
- newPathname: 'new_test.png',
- },
- ],
- v2Authors: [this.user_id],
- timestamp: this.timestamp,
- },
- ])
- })
- it('can translate multiple updates with the correct versions', function () {
- const updates = [
- {
- update: {
- doc: this.doc_id,
- pathname: '/main.tex',
- docLines: 'a\nb',
- meta: {
- user_id: this.user_id,
- ts: this.timestamp,
- },
- },
- blobHash: this.mockBlobHash,
- },
- {
- update: {
- file: this.file_id,
- pathname: '/test.png',
- url: 'filestore.example.com/test.png',
- meta: {
- user_id: this.user_id,
- ts: this.timestamp,
- },
- },
- blobHash: this.mockBlobHash,
- },
- ]
- const changes = this.UpdateTranslator.convertToChanges(
- this.project_id,
- updates
- ).map(change => change.toRaw())
- expect(changes).to.deep.equal([
- {
- authors: [],
- operations: [
- {
- pathname: 'main.tex',
- file: {
- hash: this.mockBlobHash,
- },
- },
- ],
- v2Authors: [this.user_id],
- timestamp: this.timestamp,
- },
- {
- authors: [],
- operations: [
- {
- pathname: 'test.png',
- file: {
- hash: this.mockBlobHash,
- },
- },
- ],
- v2Authors: [this.user_id],
- timestamp: this.timestamp,
- },
- ])
- })
- it('returns an error if the update has an unknown format', function () {
- const updates = [
- {
- update: {
- foo: 'bar',
- },
- },
- ]
- expect(() =>
- this.UpdateTranslator.convertToChanges(this.project_id, updates)
- ).to.throw('update with unknown format')
- })
- it('replaces backslashes with underscores in pathnames', function () {
- const updates = [
- {
- update: {
- doc: this.doc_id,
- pathname: '/\\main\\foo.tex',
- new_pathname: '/\\new_main\\foo\\bar.tex',
- meta: {
- user_id: this.user_id,
- ts: this.timestamp,
- },
- },
- },
- ]
- const changes = this.UpdateTranslator.convertToChanges(
- this.project_id,
- updates
- ).map(change => change.toRaw())
- expect(changes).to.deep.equal([
- {
- authors: [],
- operations: [
- {
- pathname: '_main_foo.tex',
- newPathname: '_new_main_foo_bar.tex',
- },
- ],
- v2Authors: [this.user_id],
- timestamp: this.timestamp,
- },
- ])
- })
- it('replaces leading asterisks with __ASTERISK__ in pathnames', function () {
- const updates = [
- {
- update: {
- file: this.file_id,
- pathname: '/test*test.png',
- meta: {
- user_id: this.user_id,
- ts: this.timestamp,
- },
- url: 'filestore.example.com/test*test.png',
- },
- blobHash: this.mockBlobHash,
- },
- ]
- const changes = this.UpdateTranslator.convertToChanges(
- this.project_id,
- updates
- ).map(change => change.toRaw())
- expect(changes).to.deep.equal([
- {
- authors: [],
- operations: [
- {
- pathname: 'test__ASTERISK__test.png',
- file: {
- hash: this.mockBlobHash,
- },
- },
- ],
- v2Authors: [this.user_id],
- timestamp: this.timestamp,
- },
- ])
- })
- it('replaces a leading space for top-level files with __SPACE__', function () {
- const updates = [
- {
- update: {
- file: this.file_id,
- pathname: '/ test.png',
- meta: {
- user_id: this.user_id,
- ts: this.timestamp,
- },
- url: 'filestore.example.com/test.png',
- },
- blobHash: this.mockBlobHash,
- },
- ]
- const changes = this.UpdateTranslator.convertToChanges(
- this.project_id,
- updates
- ).map(change => change.toRaw())
- expect(changes).to.deep.equal([
- {
- authors: [],
- operations: [
- {
- pathname: '__SPACE__test.png',
- file: {
- hash: this.mockBlobHash,
- },
- },
- ],
- v2Authors: [this.user_id],
- timestamp: this.timestamp,
- },
- ])
- })
- it('replaces leading spaces of files in subfolders with __SPACE__', function () {
- const updates = [
- {
- update: {
- file: this.file_id,
- pathname: '/folder/ test.png',
- meta: {
- user_id: this.user_id,
- ts: this.timestamp,
- },
- url: 'filestore.example.com/folder/test.png',
- },
- blobHash: this.mockBlobHash,
- },
- ]
- const changes = this.UpdateTranslator.convertToChanges(
- this.project_id,
- updates
- ).map(change => change.toRaw())
- expect(changes).to.deep.equal([
- {
- authors: [],
- operations: [
- {
- pathname: 'folder/__SPACE__test.png',
- file: {
- hash: this.mockBlobHash,
- },
- },
- ],
- v2Authors: [this.user_id],
- timestamp: this.timestamp,
- },
- ])
- })
- it('sets a null author when user_id is "anonymous-user"', function () {
- const updates = [
- {
- update: {
- doc: this.doc_id,
- pathname: '/main.tex',
- docLines: 'a\nb',
- meta: {
- user_id: 'anonymous-user',
- ts: this.timestamp,
- },
- },
- blobHash: this.mockBlobHash,
- },
- ]
- const changes = this.UpdateTranslator.convertToChanges(
- this.project_id,
- updates
- ).map(change => change.toRaw())
- expect(changes).to.deep.equal([
- {
- authors: [],
- operations: [
- {
- pathname: 'main.tex',
- file: {
- hash: this.mockBlobHash,
- },
- },
- ],
- v2Authors: [null],
- timestamp: this.timestamp,
- },
- ])
- })
- it('sets an empty array as author when there is no meta.user_id', function () {
- const updates = [
- {
- update: {
- doc: this.doc_id,
- pathname: '/main.tex',
- docLines: 'a\nb',
- meta: {
- ts: this.timestamp,
- },
- },
- blobHash: this.mockBlobHash,
- },
- ]
- const changes = this.UpdateTranslator.convertToChanges(
- this.project_id,
- updates
- ).map(change => change.toRaw())
- expect(changes).to.deep.equal([
- {
- authors: [],
- operations: [
- {
- pathname: 'main.tex',
- file: {
- hash: this.mockBlobHash,
- },
- },
- ],
- v2Authors: [],
- timestamp: this.timestamp,
- },
- ])
- })
- describe('text updates', function () {
- it('can translate insertions', function () {
- const updates = [
- {
- update: {
- doc: this.doc_id,
- op: [
- { p: 3, i: 'foo' },
- { p: 15, i: 'bar', commentIds: ['comment1'] },
- ],
- v: this.version,
- meta: {
- user_id: this.user_id,
- ts: new Date(this.timestamp).getTime(),
- pathname: '/main.tex',
- doc_length: 20,
- source: 'some-editor-id',
- },
- },
- },
- ]
- const changes = this.UpdateTranslator.convertToChanges(
- this.project_id,
- updates
- ).map(change => change.toRaw())
- expect(changes).to.deep.equal([
- {
- authors: [],
- operations: [
- {
- pathname: 'main.tex',
- textOperation: [
- 3,
- 'foo',
- 9,
- { i: 'bar', commentIds: ['comment1'] },
- 8,
- ],
- },
- ],
- v2Authors: [this.user_id],
- timestamp: this.timestamp,
- v2DocVersions: {
- '59bfd450e3028c4d40a1e9ab': {
- pathname: 'main.tex',
- v: 0,
- },
- },
- },
- ])
- })
- it('can translate deletions', function () {
- const updates = [
- {
- update: {
- doc: this.doc_id,
- op: [
- { p: 3, d: 'lo' },
- { p: 10, d: 'bar' },
- ],
- v: this.version,
- meta: {
- user_id: this.user_id,
- ts: new Date(this.timestamp).getTime(),
- pathname: '/main.tex',
- doc_length: 20,
- },
- },
- },
- ]
- const changes = this.UpdateTranslator.convertToChanges(
- this.project_id,
- updates
- ).map(change => change.toRaw())
- expect(changes).to.deep.equal([
- {
- authors: [],
- operations: [
- {
- pathname: 'main.tex',
- textOperation: [3, -2, 7, -3, 5],
- },
- ],
- v2Authors: [this.user_id],
- timestamp: this.timestamp,
- v2DocVersions: {
- '59bfd450e3028c4d40a1e9ab': {
- pathname: 'main.tex',
- v: 0,
- },
- },
- },
- ])
- })
- it('should translate retains without tracking data', function () {
- const updates = [
- {
- update: {
- doc: this.doc_id,
- op: [
- {
- p: 3,
- r: 'lo',
- },
- ],
- v: this.version,
- meta: {
- user_id: this.user_id,
- ts: new Date(this.timestamp).getTime(),
- pathname: '/main.tex',
- doc_length: 20,
- },
- },
- },
- ]
- const changes = this.UpdateTranslator.convertToChanges(
- this.project_id,
- updates
- ).map(change => change.toRaw())
- expect(changes).to.deep.equal([
- {
- authors: [],
- operations: [
- {
- pathname: 'main.tex',
- textOperation: [20],
- },
- ],
- v2Authors: [this.user_id],
- timestamp: this.timestamp,
- v2DocVersions: {
- [this.doc_id]: {
- pathname: 'main.tex',
- v: 0,
- },
- },
- },
- ])
- })
- it('can translate retains with tracking data', function () {
- const updates = [
- {
- update: {
- doc: this.doc_id,
- op: [
- {
- p: 3,
- r: 'lo',
- tracking: {
- type: 'none',
- ts: this.timestamp,
- userId: this.user_id,
- },
- },
- ],
- v: this.version,
- meta: {
- user_id: this.user_id,
- ts: new Date(this.timestamp).getTime(),
- pathname: '/main.tex',
- doc_length: 20,
- },
- },
- },
- ]
- const changes = this.UpdateTranslator.convertToChanges(
- this.project_id,
- updates
- ).map(change => change.toRaw())
- expect(changes).to.deep.equal([
- {
- authors: [],
- operations: [
- {
- pathname: 'main.tex',
- textOperation: [
- 3,
- {
- r: 2,
- tracking: {
- type: 'none',
- ts: this.timestamp,
- userId: this.user_id,
- },
- },
- 15,
- ],
- },
- ],
- v2Authors: [this.user_id],
- timestamp: this.timestamp,
- v2DocVersions: {
- '59bfd450e3028c4d40a1e9ab': {
- pathname: 'main.tex',
- v: 0,
- },
- },
- },
- ])
- })
- it('can translate insertions at the start and end (with zero retained)', function () {
- const updates = [
- {
- update: {
- doc: this.doc_id,
- op: [
- { p: 0, i: 'foo' },
- { p: 23, i: 'bar' },
- { p: 0, d: 'foo' },
- { p: 20, d: 'bar' },
- ],
- v: this.version,
- meta: {
- user_id: this.user_id,
- ts: new Date(this.timestamp).getTime(),
- pathname: '/main.tex',
- doc_length: 20,
- },
- },
- },
- ]
- const changes = this.UpdateTranslator.convertToChanges(
- this.project_id,
- updates
- ).map(change => change.toRaw())
- expect(changes).to.deep.equal([
- {
- authors: [],
- operations: [
- {
- pathname: 'main.tex',
- textOperation: [20],
- },
- ],
- v2Authors: [this.user_id],
- timestamp: this.timestamp,
- v2DocVersions: {
- '59bfd450e3028c4d40a1e9ab': {
- pathname: 'main.tex',
- v: 0,
- },
- },
- },
- ])
- })
- it('can handle operations in non-linear offset order', function () {
- const updates = [
- {
- update: {
- doc: this.doc_id,
- op: [
- { p: 15, i: 'foo' },
- { p: 3, i: 'bar' },
- ],
- v: this.version,
- meta: {
- user_id: this.user_id,
- ts: this.timestamp,
- pathname: '/main.tex',
- doc_length: 20,
- },
- },
- },
- ]
- const changes = this.UpdateTranslator.convertToChanges(
- this.project_id,
- updates
- ).map(change => change.toRaw())
- expect(changes).to.deep.equal([
- {
- authors: [],
- operations: [
- {
- pathname: 'main.tex',
- textOperation: [3, 'bar', 12, 'foo', 5],
- },
- ],
- v2Authors: [this.user_id],
- timestamp: this.timestamp,
- v2DocVersions: {
- '59bfd450e3028c4d40a1e9ab': {
- pathname: 'main.tex',
- v: 0,
- },
- },
- },
- ])
- })
- it('handles comment ops', function () {
- const updates = [
- {
- update: {
- doc: this.doc_id,
- op: [
- { p: 0, i: 'foo' },
- { p: 3, d: 'bar' },
- { p: 5, c: 'comment this', t: 'comment-id-1' },
- { p: 7, c: 'another comment', t: 'comment-id-2' },
- { p: 10, i: 'baz' },
- ],
- v: this.version,
- meta: {
- user_id: this.user_id,
- ts: new Date(this.timestamp).getTime(),
- pathname: '/main.tex',
- doc_length: 20,
- },
- },
- },
- ]
- const changes = this.UpdateTranslator.convertToChanges(
- this.project_id,
- updates
- ).map(change => change.toRaw())
- expect(changes).to.deep.equal([
- {
- authors: [],
- operations: [
- {
- pathname: 'main.tex',
- textOperation: ['foo', -3, 17],
- },
- {
- pathname: 'main.tex',
- commentId: 'comment-id-1',
- ranges: [{ pos: 5, length: 12 }],
- },
- {
- pathname: 'main.tex',
- commentId: 'comment-id-2',
- ranges: [{ pos: 7, length: 15 }],
- },
- {
- pathname: 'main.tex',
- textOperation: [10, 'baz', 10],
- },
- ],
- v2Authors: [this.user_id],
- timestamp: this.timestamp,
- v2DocVersions: {
- '59bfd450e3028c4d40a1e9ab': {
- pathname: 'main.tex',
- v: 0,
- },
- },
- },
- ])
- })
- it('handles insertions after the end of the document', function () {
- const updates = [
- {
- update: {
- doc: this.doc_id,
- op: [{ p: 3, i: '\\' }],
- v: this.version,
- meta: {
- user_id: this.user_id,
- ts: new Date(this.timestamp).getTime(),
- pathname: '/main.tex',
- doc_length: 2,
- },
- },
- },
- ]
- const changes = this.UpdateTranslator.convertToChanges(
- this.project_id,
- updates
- ).map(change => change.toRaw())
- expect(changes).to.deep.equal([
- {
- authors: [],
- operations: [
- {
- pathname: 'main.tex',
- textOperation: [2, '\\'],
- },
- ],
- v2Authors: [this.user_id],
- timestamp: this.timestamp,
- v2DocVersions: {
- '59bfd450e3028c4d40a1e9ab': {
- pathname: 'main.tex',
- v: 0,
- },
- },
- },
- ])
- })
- it('translates external source metadata into an origin', function () {
- const updates = [
- {
- update: {
- doc: this.doc_id,
- op: [{ p: 3, i: 'foo' }],
- v: this.version,
- meta: {
- user_id: this.user_id,
- ts: new Date(this.timestamp).getTime(),
- pathname: '/main.tex',
- doc_length: 20,
- type: 'external',
- source: 'dropbox',
- },
- },
- },
- ]
- const changes = this.UpdateTranslator.convertToChanges(
- this.project_id,
- updates
- ).map(change => change.toRaw())
- expect(changes).to.deep.equal([
- {
- authors: [],
- operations: [
- {
- pathname: 'main.tex',
- textOperation: [3, 'foo', 17],
- },
- ],
- v2Authors: [this.user_id],
- timestamp: this.timestamp,
- v2DocVersions: {
- '59bfd450e3028c4d40a1e9ab': {
- pathname: 'main.tex',
- v: 0,
- },
- },
- origin: { kind: 'dropbox' },
- },
- ])
- })
- it('errors on unexpected ops', function () {
- const updates = [
- {
- update: {
- doc: this.doc_id,
- op: [{ p: 5, z: 'bar' }],
- v: this.version,
- meta: {
- user_id: this.user_id,
- ts: new Date(this.timestamp).getTime(),
- pathname: '/main.tex',
- doc_length: 20,
- },
- },
- },
- ]
- expect(() => {
- this.UpdateTranslator.convertToChanges(this.project_id, updates)
- }).to.throw('unexpected op type')
- })
- })
- describe('text updates with history metadata', function () {
- it('handles deletes over tracked deletes', function () {
- const updates = [
- {
- update: {
- doc: this.doc_id,
- op: [
- { i: 'foo', p: 3, hpos: 5 },
- {
- d: 'quux',
- p: 10,
- hpos: 15,
- trackedChanges: [
- { type: 'delete', offset: 2, length: 3 },
- { type: 'delete', offset: 3, length: 1 },
- ],
- },
- { c: 'noteworthy', p: 8, t: 'comment-id', hpos: 11, hlen: 14 },
- ],
- v: this.version,
- meta: {
- user_id: this.user_id,
- ts: new Date(this.timestamp).getTime(),
- pathname: '/main.tex',
- doc_length: 20,
- history_doc_length: 30,
- source: 'some-editor-id',
- },
- },
- },
- ]
- const changes = this.UpdateTranslator.convertToChanges(
- this.project_id,
- updates
- ).map(change => change.toRaw())
- expect(changes).to.deep.equal([
- {
- authors: [],
- operations: [
- {
- pathname: 'main.tex',
- textOperation: [5, 'foo', 7, -2, 3, -1, 1, -1, 10],
- },
- {
- pathname: 'main.tex',
- commentId: 'comment-id',
- ranges: [{ pos: 11, length: 14 }],
- },
- ],
- v2Authors: [this.user_id],
- timestamp: this.timestamp,
- v2DocVersions: {
- '59bfd450e3028c4d40a1e9ab': {
- pathname: 'main.tex',
- v: 0,
- },
- },
- },
- ])
- })
- it('handles tracked delete rejections specially', function () {
- const updates = [
- {
- update: {
- doc: this.doc_id,
- op: [{ i: 'foo', p: 3, trackedDeleteRejection: true }],
- v: this.version,
- meta: {
- user_id: this.user_id,
- ts: new Date(this.timestamp).getTime(),
- pathname: '/main.tex',
- doc_length: 20,
- source: 'some-editor-id',
- },
- },
- },
- ]
- const changes = this.UpdateTranslator.convertToChanges(
- this.project_id,
- updates
- ).map(change => change.toRaw())
- expect(changes).to.deep.equal([
- {
- authors: [],
- operations: [
- {
- pathname: 'main.tex',
- textOperation: [
- 3,
- {
- r: 3,
- tracking: {
- type: 'none',
- userId: this.user_id,
- ts: new Date(this.timestamp).toISOString(),
- },
- },
- 14,
- ],
- },
- ],
- v2Authors: [this.user_id],
- timestamp: this.timestamp,
- v2DocVersions: {
- '59bfd450e3028c4d40a1e9ab': {
- pathname: 'main.tex',
- v: 0,
- },
- },
- },
- ])
- })
- it('handles tracked changes', function () {
- const updates = [
- {
- update: {
- doc: this.doc_id,
- op: [
- { i: 'inserted', p: 5 },
- { d: 'deleted', p: 20 },
- { i: 'rejected deletion', p: 30, trackedDeleteRejection: true },
- { d: 'rejected insertion', p: 50, u: true },
- ],
- v: this.version,
- meta: {
- tc: 'tracked-change-id',
- user_id: this.user_id,
- ts: new Date(this.timestamp).getTime(),
- pathname: '/main.tex',
- doc_length: 70,
- source: 'some-editor-id',
- },
- },
- },
- ]
- const changes = this.UpdateTranslator.convertToChanges(
- this.project_id,
- updates
- ).map(change => change.toRaw())
- expect(changes).to.deep.equal([
- {
- authors: [],
- operations: [
- {
- pathname: 'main.tex',
- textOperation: [
- 5,
- {
- i: 'inserted',
- tracking: {
- type: 'insert',
- userId: this.user_id,
- ts: new Date(this.timestamp).toISOString(),
- },
- },
- 7,
- {
- r: 7,
- tracking: {
- type: 'delete',
- userId: this.user_id,
- ts: new Date(this.timestamp).toISOString(),
- },
- },
- 3,
- {
- r: 17,
- tracking: {
- type: 'none',
- userId: this.user_id,
- ts: new Date(this.timestamp).toISOString(),
- },
- },
- 3,
- -18,
- 10,
- ],
- },
- ],
- v2Authors: [this.user_id],
- timestamp: this.timestamp,
- v2DocVersions: {
- '59bfd450e3028c4d40a1e9ab': {
- pathname: 'main.tex',
- v: 0,
- },
- },
- },
- ])
- })
- it('handles a delete over a mix of tracked inserts and tracked deletes', function () {
- const updates = [
- {
- update: {
- doc: this.doc_id,
- op: [
- {
- d: 'abcdef',
- p: 10,
- trackedChanges: [
- { type: 'insert', offset: 0, length: 3 },
- { type: 'delete', offset: 2, length: 10 },
- { type: 'insert', offset: 2, length: 2 },
- ],
- },
- ],
- v: this.version,
- meta: {
- tc: 'tracking-id',
- user_id: this.user_id,
- ts: new Date(this.timestamp).getTime(),
- pathname: '/main.tex',
- doc_length: 20,
- history_doc_length: 30,
- source: 'some-editor-id',
- },
- },
- },
- ]
- const changes = this.UpdateTranslator.convertToChanges(
- this.project_id,
- updates
- ).map(change => change.toRaw())
- expect(changes).to.deep.equal([
- {
- authors: [],
- operations: [
- {
- pathname: 'main.tex',
- textOperation: [
- 10,
- -3,
- 10,
- -2,
- {
- r: 1,
- tracking: {
- type: 'delete',
- userId: this.user_id,
- ts: this.timestamp,
- },
- },
- 4,
- ],
- },
- ],
- v2Authors: [this.user_id],
- timestamp: this.timestamp,
- v2DocVersions: {
- '59bfd450e3028c4d40a1e9ab': {
- pathname: 'main.tex',
- v: 0,
- },
- },
- },
- ])
- })
- })
- })
- })
|