Files
overleaf/services/docstore/test/unit/js/RangeManager.test.js
Andrew Rumble a1f1ca2028 Merge pull request #29948 from overleaf/ar/docstore-conversion-to-esm
[docstore] conversion to esm

GitOrigin-RevId: 9d255047bd7ae25f2b0b38f3a721741e8a0b7ad8
2025-12-03 09:05:42 +00:00

240 lines
6.3 KiB
JavaScript

import path from 'node:path'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { ObjectId } from 'mongodb-legacy'
const modulePath = path.join(
import.meta.dirname,
'../../../app/js/RangeManager'
)
describe('RangeManager', () => {
beforeEach(async ctx => {
vi.doMock('../../../app/js/mongodb', () => ({
default: {
ObjectId,
},
}))
ctx.RangeManager = (await import(modulePath)).default
})
describe('jsonRangesToMongo', () => {
it('should convert ObjectIds and dates to proper objects and fix comment id', ctx => {
const changeId = new ObjectId().toString()
const commentId = new ObjectId().toString()
const userId = new ObjectId().toString()
const threadId = new ObjectId().toString()
const ts = new Date().toJSON()
ctx.RangeManager.jsonRangesToMongo({
changes: [
{
id: changeId,
op: { i: 'foo', p: 3 },
metadata: {
user_id: userId,
ts,
},
},
],
comments: [
{
id: commentId,
op: { c: 'foo', p: 3, t: threadId },
},
],
}).should.deep.equal({
changes: [
{
id: new ObjectId(changeId),
op: { i: 'foo', p: 3 },
metadata: {
user_id: new ObjectId(userId),
ts: new Date(ts),
},
},
],
comments: [
{
id: new ObjectId(threadId),
op: { c: 'foo', p: 3, t: new ObjectId(threadId) },
},
],
})
})
it('should leave malformed ObjectIds as they are', ctx => {
const changeId = 'foo'
const commentId = 'bar'
const userId = 'baz'
ctx.RangeManager.jsonRangesToMongo({
changes: [
{
id: changeId,
metadata: {
user_id: userId,
},
},
],
comments: [
{
id: commentId,
},
],
}).should.deep.equal({
changes: [
{
id: changeId,
metadata: {
user_id: userId,
},
},
],
comments: [
{
id: commentId,
},
],
})
})
it('should be consistent when transformed through json -> mongo -> json', ctx => {
const changeId = new ObjectId().toString()
const userId = new ObjectId().toString()
const threadId = new ObjectId().toString()
const ts = new Date().toJSON()
const ranges1 = {
changes: [
{
id: changeId,
op: { i: 'foo', p: 3 },
metadata: {
user_id: userId,
ts,
},
},
],
comments: [
{
id: threadId,
op: { c: 'foo', p: 3, t: threadId },
},
],
}
const ranges1Copy = JSON.parse(JSON.stringify(ranges1)) // jsonRangesToMongo modifies in place
const ranges2 = JSON.parse(
JSON.stringify(ctx.RangeManager.jsonRangesToMongo(ranges1Copy))
)
ranges1.should.deep.equal(ranges2)
})
})
return describe('shouldUpdateRanges', () => {
beforeEach(ctx => {
const threadId = new ObjectId()
ctx.ranges = {
changes: [
{
id: new ObjectId(),
op: { i: 'foo', p: 3 },
metadata: {
user_id: new ObjectId(),
ts: new Date(),
},
},
],
comments: [
{
id: threadId,
op: { c: 'foo', p: 3, t: threadId },
},
],
}
ctx.ranges_copy = ctx.RangeManager.jsonRangesToMongo(
JSON.parse(JSON.stringify(ctx.ranges))
)
})
describe('with a blank new range', () => {
it('should throw an error', ctx => {
expect(() => {
ctx.RangeManager.shouldUpdateRanges(ctx.ranges, null)
}).to.throw(Error)
})
})
describe('with a blank old range', () => {
it('should treat it like {}', ctx => {
ctx.RangeManager.shouldUpdateRanges(null, {}).should.equal(false)
ctx.RangeManager.shouldUpdateRanges(null, ctx.ranges).should.equal(true)
})
})
describe('with no changes', () => {
it('should return false', ctx => {
ctx.RangeManager.shouldUpdateRanges(
ctx.ranges,
ctx.ranges_copy
).should.equal(false)
})
})
describe('with changes', () => {
it('should return true when the change id changes', ctx => {
ctx.ranges_copy.changes[0].id = new ObjectId()
ctx.RangeManager.shouldUpdateRanges(
ctx.ranges,
ctx.ranges_copy
).should.equal(true)
})
it('should return true when the change user id changes', ctx => {
ctx.ranges_copy.changes[0].metadata.user_id = new ObjectId()
ctx.RangeManager.shouldUpdateRanges(
ctx.ranges,
ctx.ranges_copy
).should.equal(true)
})
it('should return true when the change ts changes', ctx => {
ctx.ranges_copy.changes[0].metadata.ts = new Date(Date.now() + 1000)
ctx.RangeManager.shouldUpdateRanges(
ctx.ranges,
ctx.ranges_copy
).should.equal(true)
})
it('should return true when the change op changes', ctx => {
ctx.ranges_copy.changes[0].op.i = 'bar'
ctx.RangeManager.shouldUpdateRanges(
ctx.ranges,
ctx.ranges_copy
).should.equal(true)
})
it('should return true when the comment id changes', ctx => {
ctx.ranges_copy.comments[0].id = new ObjectId()
ctx.RangeManager.shouldUpdateRanges(
ctx.ranges,
ctx.ranges_copy
).should.equal(true)
})
it('should return true when the comment offset changes', ctx => {
ctx.ranges_copy.comments[0].op.p = 17
ctx.RangeManager.shouldUpdateRanges(
ctx.ranges,
ctx.ranges_copy
).should.equal(true)
})
it('should return true when the comment content changes', ctx => {
ctx.ranges_copy.comments[0].op.c = 'bar'
ctx.RangeManager.shouldUpdateRanges(
ctx.ranges,
ctx.ranges_copy
).should.equal(true)
})
})
})
})