overleaf/services/project-history/test/acceptance/js/DiffTests.js
Antoine Clausse 7f48c67512 Add prefer-node-protocol ESLint rule (#21532)
* Add `unicorn/prefer-node-protocol`

* Fix `unicorn/prefer-node-protocol` ESLint errors

* Run `npm run format:fix`

* Add sandboxed-module sourceTransformers in mocha setups

Fix `no such file or directory, open 'node:fs'` in `sandboxed-module`

* Remove `node:` in the SandboxedModule requires

* Fix new linting errors with `node:`

GitOrigin-RevId: 68f6e31e2191fcff4cb8058dd0a6914c14f59926
2024-11-11 09:04:51 +00:00

415 lines
11 KiB
JavaScript

import { expect } from 'chai'
import request from 'request'
import crypto from 'node:crypto'
import mongodb from 'mongodb-legacy'
import nock from 'nock'
import * as ProjectHistoryClient from './helpers/ProjectHistoryClient.js'
import * as ProjectHistoryApp from './helpers/ProjectHistoryApp.js'
const { ObjectId } = mongodb
const MockHistoryStore = () => nock('http://127.0.0.1:3100')
const MockWeb = () => nock('http://127.0.0.1:3000')
function createMockBlob(historyId, content) {
const sha = crypto.createHash('sha1').update(content).digest('hex')
MockHistoryStore()
.get(`/api/projects/${historyId}/blobs/${sha}`)
.reply(200, content)
.persist()
return sha
}
describe('Diffs', function () {
beforeEach(function (done) {
ProjectHistoryApp.ensureRunning(error => {
if (error) {
throw error
}
this.historyId = new ObjectId().toString()
this.projectId = new ObjectId().toString()
MockHistoryStore().post('/api/projects').reply(200, {
projectId: this.historyId,
})
MockWeb()
.get(`/project/${this.projectId}/details`)
.reply(200, {
name: 'Test Project',
overleaf: { history: { id: this.historyId } },
})
ProjectHistoryClient.initializeProject(this.historyId, error => {
if (error) {
return done(error)
}
done()
})
})
})
afterEach(function () {
nock.cleanAll()
})
it('should return a diff of the updates to a doc from a single chunk', function (done) {
this.blob = 'one two three five'
this.sha = createMockBlob(this.historyId, this.blob)
this.v2AuthorId = '123456789'
MockHistoryStore()
.get(`/api/projects/${this.historyId}/versions/6/history`)
.reply(200, {
chunk: {
history: {
snapshot: {
files: {
'foo.tex': {
hash: this.sha,
stringLength: this.blob.length,
},
},
},
changes: [
{
operations: [
{
pathname: 'foo.tex',
textOperation: [13, ' four', 5],
},
],
timestamp: '2017-12-04T10:29:17.786Z',
authors: [31],
},
{
operations: [
{
pathname: 'foo.tex',
textOperation: [4, -4, 15],
},
],
timestamp: '2017-12-04T10:29:22.905Z',
authors: [31],
},
{
operations: [
{
pathname: 'foo.tex',
textOperation: [19, ' six'],
},
],
timestamp: '2017-12-04T10:29:26.120Z',
v2Authors: [this.v2AuthorId],
},
],
},
startVersion: 3,
},
authors: [31],
})
ProjectHistoryClient.getDiff(
this.projectId,
'foo.tex',
3,
6,
(error, diff) => {
if (error) {
throw error
}
expect(diff).to.deep.equal({
diff: [
{
u: 'one ',
},
{
d: 'two ',
meta: {
users: [31],
start_ts: 1512383362905,
end_ts: 1512383362905,
},
},
{
u: 'three',
},
{
i: ' four',
meta: {
users: [31],
start_ts: 1512383357786,
end_ts: 1512383357786,
},
},
{
u: ' five',
},
{
i: ' six',
meta: {
users: [this.v2AuthorId],
start_ts: 1512383366120,
end_ts: 1512383366120,
},
},
],
})
done()
}
)
})
it('should return a diff of the updates to a doc across multiple chunks', function (done) {
MockHistoryStore()
.get(`/api/projects/${this.historyId}/versions/5/history`)
.reply(200, {
chunk: {
history: {
snapshot: {
files: {
'foo.tex': {
hash: createMockBlob(this.historyId, 'one two three five'),
stringLength: 'one three four five'.length,
},
},
},
changes: [
{
operations: [
{
pathname: 'foo.tex',
textOperation: [13, ' four', 5],
},
],
timestamp: '2017-12-04T10:29:17.786Z',
authors: [31],
},
{
operations: [
{
pathname: 'foo.tex',
textOperation: [4, -4, 15],
},
],
timestamp: '2017-12-04T10:29:22.905Z',
authors: [31],
},
],
},
startVersion: 3,
},
authors: [{ id: 31, email: 'james.allen@overleaf.com', name: 'James' }],
})
MockHistoryStore()
.get(`/api/projects/${this.historyId}/versions/6/history`)
.reply(200, {
chunk: {
history: {
snapshot: {
files: {
'foo.tex': {
hash: createMockBlob(this.historyId, 'one three four five'),
stringLength: 'one three four five'.length,
},
},
},
changes: [
{
operations: [
{
pathname: 'foo.tex',
textOperation: [19, ' six'],
},
],
timestamp: '2017-12-04T10:29:26.120Z',
authors: [31],
},
{
operations: [
{
pathname: 'foo.tex',
textOperation: [23, ' seven'],
},
],
timestamp: '2017-12-04T10:29:26.120Z',
authors: [31],
},
],
},
startVersion: 5,
},
authors: [{ id: 31, email: 'james.allen@overleaf.com', name: 'James' }],
})
ProjectHistoryClient.getDiff(
this.projectId,
'foo.tex',
4,
6,
(error, diff) => {
if (error) {
throw error
}
expect(diff).to.deep.equal({
diff: [
{
u: 'one ',
},
{
d: 'two ',
meta: {
users: [31],
start_ts: 1512383362905,
end_ts: 1512383362905,
},
},
{
u: 'three four five',
},
{
i: ' six',
meta: {
users: [31],
start_ts: 1512383366120,
end_ts: 1512383366120,
},
},
],
})
done()
}
)
})
it('should return a 404 when there are no changes for the file in the range', function (done) {
this.blob = 'one two three five'
this.sha = createMockBlob(this.historyId, this.blob)
MockHistoryStore()
.get(`/api/projects/${this.historyId}/versions/6/history`)
.reply(200, {
chunk: {
history: {
snapshot: {
files: {
'foo.tex': {
hash: this.sha,
stringLength: this.blob.length,
},
},
},
changes: [
{
operations: [
{
pathname: 'foo.tex',
textOperation: [13, ' four', 5],
},
],
timestamp: '2017-12-04T10:29:17.786Z',
authors: [31],
},
],
},
startVersion: 3,
},
authors: [31],
})
request.get(
{
url: `http://127.0.0.1:3054/project/${this.projectId}/diff`,
qs: {
pathname: 'not_here.tex',
from: 3,
to: 6,
},
json: true,
},
(error, res, body) => {
if (error) {
throw error
}
expect(res.statusCode).to.equal(404)
done()
}
)
})
it('should return a binary flag with a diff of a binary file', function (done) {
this.blob = 'one two three five'
this.sha = createMockBlob(this.historyId, this.blob)
this.binaryBlob = Buffer.from([1, 2, 3, 4])
this.binarySha = createMockBlob(this.historyId, this.binaryBlob)
MockHistoryStore()
.get(`/api/projects/${this.historyId}/versions/6/history`)
.reply(200, {
chunk: {
history: {
snapshot: {
files: {
'binary.tex': {
hash: this.binarySha,
byteLength: this.binaryBlob.length, // Indicates binary
},
'foo.tex': {
hash: this.sha,
stringLength: this.blob.length, // Indicates binary
},
},
},
changes: [
{
operations: [
{
pathname: 'foo.tex',
textOperation: [13, ' four', 5],
},
],
timestamp: '2017-12-04T10:29:17.786Z',
authors: [31],
},
{
operations: [
{
pathname: 'foo.tex',
textOperation: [4, -4, 15],
},
],
timestamp: '2017-12-04T10:29:22.905Z',
authors: [31],
},
{
operations: [
{
pathname: 'foo.tex',
textOperation: [19, ' six'],
},
],
timestamp: '2017-12-04T10:29:26.120Z',
authors: [31],
},
],
},
startVersion: 3,
},
authors: [{ id: 31, email: 'james.allen@overleaf.com', name: 'James' }],
})
ProjectHistoryClient.getDiff(
this.projectId,
'binary.tex',
3,
6,
(error, diff) => {
if (error) {
throw error
}
expect(diff).to.deep.equal({
diff: {
binary: true,
},
})
done()
}
)
})
})