Procházet zdrojové kódy

decaffeinate: Convert AppendingUpdatesTests.coffee and 11 other files to JS

decaffeinate před 6 roky
rodič
revize
11c39cde65

+ 347 - 271
services/track-changes/test/acceptance/coffee/AppendingUpdatesTests.js

@@ -1,311 +1,387 @@
-sinon = require "sinon"
-chai = require("chai")
-chai.should()
-expect = chai.expect
-mongojs = require "../../../app/js/mongojs"
-ObjectId = mongojs.ObjectId
-Settings = require "settings-sharelatex"
-request = require "request"
-rclient = require("redis").createClient(Settings.redis.history) # Only works locally for now
-
-TrackChangesApp = require "./helpers/TrackChangesApp"
-TrackChangesClient = require "./helpers/TrackChangesClient"
-MockWebApi = require "./helpers/MockWebApi"
-
-describe "Appending doc ops to the history", ->
-	before (done)->
-		TrackChangesApp.ensureRunning done
-
-	describe "when the history does not exist yet", ->
-		before (done) ->
-			@project_id = ObjectId().toString()
-			@doc_id = ObjectId().toString()
-			@user_id = ObjectId().toString()
-			MockWebApi.projects[@project_id] = features: versioning: false
-			TrackChangesClient.pushRawUpdates @project_id, @doc_id, [{
-				op: [{ i: "f", p: 3 }]
-				meta: { ts: Date.now(), user_id: @user_id }
+/*
+ * decaffeinate suggestions:
+ * DS102: Remove unnecessary code created because of implicit returns
+ * DS207: Consider shorter variations of null checks
+ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
+ */
+const sinon = require("sinon");
+const chai = require("chai");
+chai.should();
+const { expect } = chai;
+const mongojs = require("../../../app/js/mongojs");
+const { ObjectId } = mongojs;
+const Settings = require("settings-sharelatex");
+const request = require("request");
+const rclient = require("redis").createClient(Settings.redis.history); // Only works locally for now
+
+const TrackChangesApp = require("./helpers/TrackChangesApp");
+const TrackChangesClient = require("./helpers/TrackChangesClient");
+const MockWebApi = require("./helpers/MockWebApi");
+
+describe("Appending doc ops to the history", function() {
+	before(done=> TrackChangesApp.ensureRunning(done));
+
+	describe("when the history does not exist yet", function() {
+		before(function(done) {
+			this.project_id = ObjectId().toString();
+			this.doc_id = ObjectId().toString();
+			this.user_id = ObjectId().toString();
+			MockWebApi.projects[this.project_id] = {features: {versioning: false}};
+			TrackChangesClient.pushRawUpdates(this.project_id, this.doc_id, [{
+				op: [{ i: "f", p: 3 }],
+				meta: { ts: Date.now(), user_id: this.user_id },
 				v: 3
 			}, {
-				op: [{ i: "o", p: 4 }]
-				meta: { ts: Date.now(), user_id: @user_id }
+				op: [{ i: "o", p: 4 }],
+				meta: { ts: Date.now(), user_id: this.user_id },
 				v: 4
 			}, {
-				op: [{ i: "o", p: 5 }]
-				meta: { ts: Date.now(), user_id: @user_id }
+				op: [{ i: "o", p: 5 }],
+				meta: { ts: Date.now(), user_id: this.user_id },
 				v: 5
-			}], (error) =>
-				throw error if error?
-				TrackChangesClient.flushAndGetCompressedUpdates @project_id, @doc_id, (error, @updates) =>
-					throw error if error?
-					done()
-			return null
-
-		it "should insert the compressed op into mongo", ->
-			expect(@updates[0].pack[0].op).to.deep.equal [{
+			}], error => {
+				if (error != null) { throw error; }
+				return TrackChangesClient.flushAndGetCompressedUpdates(this.project_id, this.doc_id, (error, updates) => {
+					this.updates = updates;
+					if (error != null) { throw error; }
+					return done();
+				});
+			});
+			return null;
+		});
+
+		it("should insert the compressed op into mongo", function() {
+			return expect(this.updates[0].pack[0].op).to.deep.equal([{
 				p: 3, i: "foo"
-			}]
-
-		it "should insert the correct version number into mongo", ->
-			expect(@updates[0].v).to.equal 5
-
-		it "should store the doc id", ->
-			expect(@updates[0].doc_id.toString()).to.equal @doc_id
-
-		it "should store the project id", ->
-			expect(@updates[0].project_id.toString()).to.equal @project_id
-
-		it "should clear the doc from the DocsWithHistoryOps set", (done) ->
-			rclient.sismember "DocsWithHistoryOps:#{@project_id}", @doc_id, (error, member) ->
-				member.should.equal 0
-				done()
-			return null
-
-	describe "when the history has already been started", ->
-		beforeEach (done) ->
-			@project_id = ObjectId().toString()
-			@doc_id = ObjectId().toString()
-			@user_id = ObjectId().toString()
-			MockWebApi.projects[@project_id] = features: versioning: false
-			TrackChangesClient.pushRawUpdates @project_id, @doc_id, [{
-				op: [{ i: "f", p: 3 }]
-				meta: { ts: Date.now(), user_id: @user_id }
+			}]);
+	});
+
+		it("should insert the correct version number into mongo", function() {
+			return expect(this.updates[0].v).to.equal(5);
+		});
+
+		it("should store the doc id", function() {
+			return expect(this.updates[0].doc_id.toString()).to.equal(this.doc_id);
+		});
+
+		it("should store the project id", function() {
+			return expect(this.updates[0].project_id.toString()).to.equal(this.project_id);
+		});
+
+		return it("should clear the doc from the DocsWithHistoryOps set", function(done) {
+			rclient.sismember(`DocsWithHistoryOps:${this.project_id}`, this.doc_id, function(error, member) {
+				member.should.equal(0);
+				return done();
+			});
+			return null;
+		});
+	});
+
+	describe("when the history has already been started", function() {
+		beforeEach(function(done) {
+			this.project_id = ObjectId().toString();
+			this.doc_id = ObjectId().toString();
+			this.user_id = ObjectId().toString();
+			MockWebApi.projects[this.project_id] = {features: {versioning: false}};
+			TrackChangesClient.pushRawUpdates(this.project_id, this.doc_id, [{
+				op: [{ i: "f", p: 3 }],
+				meta: { ts: Date.now(), user_id: this.user_id },
 				v: 3
 			}, {
-				op: [{ i: "o", p: 4 }]
-				meta: { ts: Date.now(), user_id: @user_id }
+				op: [{ i: "o", p: 4 }],
+				meta: { ts: Date.now(), user_id: this.user_id },
 				v: 4
 			}, {
-				op: [{ i: "o", p: 5 }]
-				meta: { ts: Date.now(), user_id: @user_id }
+				op: [{ i: "o", p: 5 }],
+				meta: { ts: Date.now(), user_id: this.user_id },
 				v: 5
-			}], (error) =>
-				throw error if error?
-				TrackChangesClient.flushAndGetCompressedUpdates @project_id, @doc_id, (error, updates) =>
-					throw error if error?
-					done()
-			return null
-
-		describe "when the updates are recent and from the same user", ->
-			beforeEach (done) ->
-				TrackChangesClient.pushRawUpdates @project_id, @doc_id, [{
-					op: [{ i: "b", p: 6 }]
-					meta: { ts: Date.now(), user_id: @user_id }
+			}], error => {
+				if (error != null) { throw error; }
+				return TrackChangesClient.flushAndGetCompressedUpdates(this.project_id, this.doc_id, (error, updates) => {
+					if (error != null) { throw error; }
+					return done();
+				});
+			});
+			return null;
+		});
+
+		describe("when the updates are recent and from the same user", function() {
+			beforeEach(function(done) {
+				TrackChangesClient.pushRawUpdates(this.project_id, this.doc_id, [{
+					op: [{ i: "b", p: 6 }],
+					meta: { ts: Date.now(), user_id: this.user_id },
 					v: 6
 				}, {
-					op: [{ i: "a", p: 7 }]
-					meta: { ts: Date.now(), user_id: @user_id }
+					op: [{ i: "a", p: 7 }],
+					meta: { ts: Date.now(), user_id: this.user_id },
 					v: 7
 				}, {
-					op: [{ i: "r", p: 8 }]
-					meta: { ts: Date.now(), user_id: @user_id }
+					op: [{ i: "r", p: 8 }],
+					meta: { ts: Date.now(), user_id: this.user_id },
 					v: 8
-				}], (error) =>
-					throw error if error?
-					TrackChangesClient.flushAndGetCompressedUpdates @project_id, @doc_id, (error, @updates) =>
-						throw error if error?
-						done()
-				return null
-
-			it "should combine all the updates into one pack", ->
-				expect(@updates[0].pack[1].op).to.deep.equal [{
+				}], error => {
+					if (error != null) { throw error; }
+					return TrackChangesClient.flushAndGetCompressedUpdates(this.project_id, this.doc_id, (error, updates) => {
+						this.updates = updates;
+						if (error != null) { throw error; }
+						return done();
+					});
+				});
+				return null;
+			});
+
+			it("should combine all the updates into one pack", function() {
+				return expect(this.updates[0].pack[1].op).to.deep.equal([{
 					p: 6, i: "bar"
-				}]
+				}]);
+		});
 
-			it "should insert the correct version number into mongo", ->
-				expect(@updates[0].v_end).to.equal 8
+			return it("should insert the correct version number into mongo", function() {
+				return expect(this.updates[0].v_end).to.equal(8);
+			});
+		});
 
 
-		describe "when the updates are far apart", ->
-			beforeEach (done) ->
-				oneDay = 24 * 60 * 60 * 1000
-				TrackChangesClient.pushRawUpdates @project_id, @doc_id, [{
-					op: [{ i: "b", p: 6 }]
-					meta: { ts: Date.now() + oneDay, user_id: @user_id }
+		return describe("when the updates are far apart", function() {
+			beforeEach(function(done) {
+				const oneDay = 24 * 60 * 60 * 1000;
+				TrackChangesClient.pushRawUpdates(this.project_id, this.doc_id, [{
+					op: [{ i: "b", p: 6 }],
+					meta: { ts: Date.now() + oneDay, user_id: this.user_id },
 					v: 6
 				}, {
-					op: [{ i: "a", p: 7 }]
-					meta: { ts: Date.now() + oneDay, user_id: @user_id }
+					op: [{ i: "a", p: 7 }],
+					meta: { ts: Date.now() + oneDay, user_id: this.user_id },
 					v: 7
 				}, {
-					op: [{ i: "r", p: 8 }]
-					meta: { ts: Date.now() + oneDay, user_id: @user_id }
+					op: [{ i: "r", p: 8 }],
+					meta: { ts: Date.now() + oneDay, user_id: this.user_id },
 					v: 8
-				}], (error) =>
-					throw error if error?
-					TrackChangesClient.flushAndGetCompressedUpdates @project_id, @doc_id, (error, @updates) =>
-						throw error if error?
-						done()
-				return null
-
-			it "should combine the updates into one pack", ->
-				expect(@updates[0].pack[0].op).to.deep.equal [{
+				}], error => {
+					if (error != null) { throw error; }
+					return TrackChangesClient.flushAndGetCompressedUpdates(this.project_id, this.doc_id, (error, updates) => {
+						this.updates = updates;
+						if (error != null) { throw error; }
+						return done();
+					});
+				});
+				return null;
+			});
+
+			return it("should combine the updates into one pack", function() {
+				expect(this.updates[0].pack[0].op).to.deep.equal([{
 					p: 3, i: "foo"
-				}]
-				expect(@updates[0].pack[1].op).to.deep.equal [{
+				}]);
+				return expect(this.updates[0].pack[1].op).to.deep.equal([{
 					p: 6, i: "bar"
-				}]
-
-	describe "when the updates need processing in batches", ->
-		before (done) ->
-			@project_id = ObjectId().toString()
-			@doc_id = ObjectId().toString()
-			@user_id = ObjectId().toString()
-			MockWebApi.projects[@project_id] = features: versioning: false
-			updates = []
-			@expectedOp = [{ p:0, i: "" }]
-			for i in [0..250]
-				updates.push {
-					op: [{i: "a", p: 0}]
-					meta: { ts: Date.now(), user_id: @user_id }
+				}]);
+		});
+	});
+});
+
+	describe("when the updates need processing in batches", function() {
+		before(function(done) {
+			this.project_id = ObjectId().toString();
+			this.doc_id = ObjectId().toString();
+			this.user_id = ObjectId().toString();
+			MockWebApi.projects[this.project_id] = {features: {versioning: false}};
+			const updates = [];
+			this.expectedOp = [{ p:0, i: "" }];
+			for (let i = 0; i <= 250; i++) {
+				updates.push({
+					op: [{i: "a", p: 0}],
+					meta: { ts: Date.now(), user_id: this.user_id },
 					v: i
-				}
-				@expectedOp[0].i = "a" + @expectedOp[0].i
-
-			TrackChangesClient.pushRawUpdates @project_id, @doc_id, updates, (error) =>
-				throw error if error?
-				TrackChangesClient.flushAndGetCompressedUpdates @project_id, @doc_id, (error, @updates) =>
-					throw error if error?
-					done()
-			return null
-
-		it "should concat the compressed op into mongo", ->
-			expect(@updates[0].pack.length).to.deep.equal 3  # batch size is 100
-
-		it "should insert the correct version number into mongo", ->
-			expect(@updates[0].v_end).to.equal 250
-
-
-	describe "when there are multiple ops in each update", ->
-		before (done) ->
-			@project_id = ObjectId().toString()
-			@doc_id = ObjectId().toString()
-			@user_id = ObjectId().toString()
-			MockWebApi.projects[@project_id] = features: versioning: false
-			oneDay = 24 * 60 * 60 * 1000
-			TrackChangesClient.pushRawUpdates @project_id, @doc_id, [{
-				op: [{ i: "f", p: 3 }, { i: "o", p: 4 }, { i: "o", p: 5 }]
-				meta: { ts: Date.now(), user_id: @user_id }
+				});
+				this.expectedOp[0].i = `a${this.expectedOp[0].i}`;
+			}
+
+			TrackChangesClient.pushRawUpdates(this.project_id, this.doc_id, updates, error => {
+				if (error != null) { throw error; }
+				return TrackChangesClient.flushAndGetCompressedUpdates(this.project_id, this.doc_id, (error, updates1) => {
+					this.updates = updates1;
+					if (error != null) { throw error; }
+					return done();
+				});
+			});
+			return null;
+		});
+
+		it("should concat the compressed op into mongo", function() {
+			return expect(this.updates[0].pack.length).to.deep.equal(3);
+		});  // batch size is 100
+
+		return it("should insert the correct version number into mongo", function() {
+			return expect(this.updates[0].v_end).to.equal(250);
+		});
+	});
+
+
+	describe("when there are multiple ops in each update", function() {
+		before(function(done) {
+			this.project_id = ObjectId().toString();
+			this.doc_id = ObjectId().toString();
+			this.user_id = ObjectId().toString();
+			MockWebApi.projects[this.project_id] = {features: {versioning: false}};
+			const oneDay = 24 * 60 * 60 * 1000;
+			TrackChangesClient.pushRawUpdates(this.project_id, this.doc_id, [{
+				op: [{ i: "f", p: 3 }, { i: "o", p: 4 }, { i: "o", p: 5 }],
+				meta: { ts: Date.now(), user_id: this.user_id },
 				v: 3
 			}, {
-				op: [{ i: "b", p: 6 }, { i: "a", p: 7 }, { i: "r", p: 8 }]
-				meta: { ts: Date.now() + oneDay, user_id: @user_id }
+				op: [{ i: "b", p: 6 }, { i: "a", p: 7 }, { i: "r", p: 8 }],
+				meta: { ts: Date.now() + oneDay, user_id: this.user_id },
 				v: 4
-			}], (error) =>
-				throw error if error?
-				TrackChangesClient.flushAndGetCompressedUpdates @project_id, @doc_id, (error, @updates) =>
-					throw error if error?
-					done()
-			return null
-
-		it "should insert the compressed ops into mongo", ->
-			expect(@updates[0].pack[0].op).to.deep.equal [{
+			}], error => {
+				if (error != null) { throw error; }
+				return TrackChangesClient.flushAndGetCompressedUpdates(this.project_id, this.doc_id, (error, updates) => {
+					this.updates = updates;
+					if (error != null) { throw error; }
+					return done();
+				});
+			});
+			return null;
+		});
+
+		it("should insert the compressed ops into mongo", function() {
+			expect(this.updates[0].pack[0].op).to.deep.equal([{
 				p: 3, i: "foo"
-			}]
-			expect(@updates[0].pack[1].op).to.deep.equal [{
+			}]);
+			return expect(this.updates[0].pack[1].op).to.deep.equal([{
 				p: 6, i: "bar"
-			}]
-
-		it "should insert the correct version numbers into mongo", ->
-			expect(@updates[0].pack[0].v).to.equal 3
-			expect(@updates[0].pack[1].v).to.equal 4
-
-	describe "when there is a no-op update", ->
-		before (done) ->
-			@project_id = ObjectId().toString()
-			@doc_id = ObjectId().toString()
-			@user_id = ObjectId().toString()
-			MockWebApi.projects[@project_id] = features: versioning: false
-			oneDay = 24 * 60 * 60 * 1000
-			TrackChangesClient.pushRawUpdates @project_id, @doc_id, [{
-				op: []
-				meta: { ts: Date.now(), user_id: @user_id }
+			}]);
+	});
+
+		return it("should insert the correct version numbers into mongo", function() {
+			expect(this.updates[0].pack[0].v).to.equal(3);
+			return expect(this.updates[0].pack[1].v).to.equal(4);
+		});
+	});
+
+	describe("when there is a no-op update", function() {
+		before(function(done) {
+			this.project_id = ObjectId().toString();
+			this.doc_id = ObjectId().toString();
+			this.user_id = ObjectId().toString();
+			MockWebApi.projects[this.project_id] = {features: {versioning: false}};
+			const oneDay = 24 * 60 * 60 * 1000;
+			TrackChangesClient.pushRawUpdates(this.project_id, this.doc_id, [{
+				op: [],
+				meta: { ts: Date.now(), user_id: this.user_id },
 				v: 3
 			}, {
-				op: [{ i: "foo", p: 3 }]
-				meta: { ts: Date.now() + oneDay, user_id: @user_id }
+				op: [{ i: "foo", p: 3 }],
+				meta: { ts: Date.now() + oneDay, user_id: this.user_id },
 				v: 4
-			}], (error) =>
-				throw error if error?
-				TrackChangesClient.flushAndGetCompressedUpdates @project_id, @doc_id, (error, @updates) =>
-					throw error if error?
-					done()
-			return null
-
-		it "should insert the compressed no-op into mongo", ->
-			expect(@updates[0].pack[0].op).to.deep.equal []
-
-
-		it "should insert the compressed next update into mongo", ->
-			expect(@updates[0].pack[1].op).to.deep.equal [{
+			}], error => {
+				if (error != null) { throw error; }
+				return TrackChangesClient.flushAndGetCompressedUpdates(this.project_id, this.doc_id, (error, updates) => {
+					this.updates = updates;
+					if (error != null) { throw error; }
+					return done();
+				});
+			});
+			return null;
+		});
+
+		it("should insert the compressed no-op into mongo", function() {
+			return expect(this.updates[0].pack[0].op).to.deep.equal([]);
+	});
+
+
+		it("should insert the compressed next update into mongo", function() {
+			return expect(this.updates[0].pack[1].op).to.deep.equal([{
 				p: 3, i: "foo"
-			}]
-
-		it "should insert the correct version numbers into mongo", ->
-			expect(@updates[0].pack[0].v).to.equal 3
-			expect(@updates[0].pack[1].v).to.equal 4
-
-	describe "when there is a comment update", ->
-		before (done) ->
-			@project_id = ObjectId().toString()
-			@doc_id = ObjectId().toString()
-			@user_id = ObjectId().toString()
-			MockWebApi.projects[@project_id] = features: versioning: false
-			TrackChangesClient.pushRawUpdates @project_id, @doc_id, [{
-				op: [{ c: "foo", p: 3 }, {d: "bar", p: 6}]
-				meta: { ts: Date.now(), user_id: @user_id }
+			}]);
+	});
+
+		return it("should insert the correct version numbers into mongo", function() {
+			expect(this.updates[0].pack[0].v).to.equal(3);
+			return expect(this.updates[0].pack[1].v).to.equal(4);
+		});
+	});
+
+	describe("when there is a comment update", function() {
+		before(function(done) {
+			this.project_id = ObjectId().toString();
+			this.doc_id = ObjectId().toString();
+			this.user_id = ObjectId().toString();
+			MockWebApi.projects[this.project_id] = {features: {versioning: false}};
+			TrackChangesClient.pushRawUpdates(this.project_id, this.doc_id, [{
+				op: [{ c: "foo", p: 3 }, {d: "bar", p: 6}],
+				meta: { ts: Date.now(), user_id: this.user_id },
 				v: 3
-			}], (error) =>
-				throw error if error?
-				TrackChangesClient.flushAndGetCompressedUpdates @project_id, @doc_id, (error, @updates) =>
-					throw error if error?
-					done()
-			return null
-
-		it "should ignore the comment op", ->
-			expect(@updates[0].pack[0].op).to.deep.equal [{d: "bar", p: 6}]
-
-		it "should insert the correct version numbers into mongo", ->
-			expect(@updates[0].pack[0].v).to.equal 3
-
-	describe "when the project has versioning enabled", ->
-		before (done) ->
-			@project_id = ObjectId().toString()
-			@doc_id = ObjectId().toString()
-			@user_id = ObjectId().toString()
-			MockWebApi.projects[@project_id] = features: versioning: true
-
-			TrackChangesClient.pushRawUpdates @project_id, @doc_id, [{
-				op: [{ i: "f", p: 3 }]
-				meta: { ts: Date.now(), user_id: @user_id }
+			}], error => {
+				if (error != null) { throw error; }
+				return TrackChangesClient.flushAndGetCompressedUpdates(this.project_id, this.doc_id, (error, updates) => {
+					this.updates = updates;
+					if (error != null) { throw error; }
+					return done();
+				});
+			});
+			return null;
+		});
+
+		it("should ignore the comment op", function() {
+			return expect(this.updates[0].pack[0].op).to.deep.equal([{d: "bar", p: 6}]);
+	});
+
+		return it("should insert the correct version numbers into mongo", function() {
+			return expect(this.updates[0].pack[0].v).to.equal(3);
+		});
+	});
+
+	describe("when the project has versioning enabled", function() {
+		before(function(done) {
+			this.project_id = ObjectId().toString();
+			this.doc_id = ObjectId().toString();
+			this.user_id = ObjectId().toString();
+			MockWebApi.projects[this.project_id] = {features: {versioning: true}};
+
+			TrackChangesClient.pushRawUpdates(this.project_id, this.doc_id, [{
+				op: [{ i: "f", p: 3 }],
+				meta: { ts: Date.now(), user_id: this.user_id },
 				v: 3
-			}], (error) =>
-				throw error if error?
-				TrackChangesClient.flushAndGetCompressedUpdates @project_id, @doc_id, (error, @updates) =>
-					throw error if error?
-					done()
-			return null
-
-		it "should not add a expiresAt entry in the update in mongo", ->
-			expect(@updates[0].expiresAt).to.be.undefined
-
-	describe "when the project does not have versioning enabled", ->
-		before (done) ->
-			@project_id = ObjectId().toString()
-			@doc_id = ObjectId().toString()
-			@user_id = ObjectId().toString()
-			MockWebApi.projects[@project_id] = features: versioning: false
-
-			TrackChangesClient.pushRawUpdates @project_id, @doc_id, [{
-				op: [{ i: "f", p: 3 }]
-				meta: { ts: Date.now(), user_id: @user_id }
+			}], error => {
+				if (error != null) { throw error; }
+				return TrackChangesClient.flushAndGetCompressedUpdates(this.project_id, this.doc_id, (error, updates) => {
+					this.updates = updates;
+					if (error != null) { throw error; }
+					return done();
+				});
+			});
+			return null;
+		});
+
+		return it("should not add a expiresAt entry in the update in mongo", function() {
+			return expect(this.updates[0].expiresAt).to.be.undefined;
+		});
+	});
+
+	return describe("when the project does not have versioning enabled", function() {
+		before(function(done) {
+			this.project_id = ObjectId().toString();
+			this.doc_id = ObjectId().toString();
+			this.user_id = ObjectId().toString();
+			MockWebApi.projects[this.project_id] = {features: {versioning: false}};
+
+			TrackChangesClient.pushRawUpdates(this.project_id, this.doc_id, [{
+				op: [{ i: "f", p: 3 }],
+				meta: { ts: Date.now(), user_id: this.user_id },
 				v: 3
-			}], (error) =>
-				throw error if error?
-				TrackChangesClient.flushAndGetCompressedUpdates @project_id, @doc_id, (error, @updates) =>
-					throw error if error?
-					done()
-			return null
-
-		it "should add a expiresAt entry in the update in mongo", ->
-			expect(@updates[0].expiresAt).to.exist
+			}], error => {
+				if (error != null) { throw error; }
+				return TrackChangesClient.flushAndGetCompressedUpdates(this.project_id, this.doc_id, (error, updates) => {
+					this.updates = updates;
+					if (error != null) { throw error; }
+					return done();
+				});
+			});
+			return null;
+		});
+
+		return it("should add a expiresAt entry in the update in mongo", function() {
+			return expect(this.updates[0].expiresAt).to.exist;
+		});
+	});
+});

+ 178 - 131
services/track-changes/test/acceptance/coffee/ArchivingUpdatesTests.js

@@ -1,134 +1,181 @@
-sinon = require "sinon"
-chai = require("chai")
-chai.should()
-expect = chai.expect
-mongojs = require "../../../app/js/mongojs"
-db = mongojs.db
-ObjectId = mongojs.ObjectId
-Settings = require "settings-sharelatex"
-request = require "request"
-rclient = require("redis").createClient(Settings.redis.history) # Only works locally for now
-
-TrackChangesApp = require "./helpers/TrackChangesApp"
-TrackChangesClient = require "./helpers/TrackChangesClient"
-MockDocStoreApi = require "./helpers/MockDocStoreApi"
-MockWebApi = require "./helpers/MockWebApi"
-
-describe "Archiving updates", ->
-	before (done) ->
-		if Settings?.trackchanges?.s3?.key.length < 1
-			message = new Error("s3 keys not setup, this test setup will fail")
-			return done(message)
-
-		TrackChangesClient.waitForS3 done
-
-	before (done) ->
-		@now = Date.now()
-		@to = @now
-		@user_id = ObjectId().toString()
-		@doc_id = ObjectId().toString()
-		@project_id = ObjectId().toString()
-
-		@minutes = 60 * 1000
-		@hours = 60 * @minutes
-
-		MockWebApi.projects[@project_id] =
-			features:
+/*
+ * decaffeinate suggestions:
+ * DS102: Remove unnecessary code created because of implicit returns
+ * DS103: Rewrite code to no longer use __guard__
+ * DS202: Simplify dynamic range loops
+ * DS207: Consider shorter variations of null checks
+ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
+ */
+const sinon = require("sinon");
+const chai = require("chai");
+chai.should();
+const { expect } = chai;
+const mongojs = require("../../../app/js/mongojs");
+const { db } = mongojs;
+const { ObjectId } = mongojs;
+const Settings = require("settings-sharelatex");
+const request = require("request");
+const rclient = require("redis").createClient(Settings.redis.history); // Only works locally for now
+
+const TrackChangesApp = require("./helpers/TrackChangesApp");
+const TrackChangesClient = require("./helpers/TrackChangesClient");
+const MockDocStoreApi = require("./helpers/MockDocStoreApi");
+const MockWebApi = require("./helpers/MockWebApi");
+
+describe("Archiving updates", function() {
+	before(function(done) {
+		if (__guard__(__guard__(Settings != null ? Settings.trackchanges : undefined, x1 => x1.s3), x => x.key.length) < 1) {
+			const message = new Error("s3 keys not setup, this test setup will fail");
+			return done(message);
+		}
+
+		return TrackChangesClient.waitForS3(done);
+	});
+
+	before(function(done) {
+		this.now = Date.now();
+		this.to = this.now;
+		this.user_id = ObjectId().toString();
+		this.doc_id = ObjectId().toString();
+		this.project_id = ObjectId().toString();
+
+		this.minutes = 60 * 1000;
+		this.hours = 60 * this.minutes;
+
+		MockWebApi.projects[this.project_id] = {
+			features: {
 				versioning: true
-		sinon.spy MockWebApi, "getProjectDetails"
-
-		MockWebApi.users[@user_id] = @user =
-			email: "user@sharelatex.com"
-			first_name: "Leo"
-			last_name: "Lion"
-			id: @user_id
-		sinon.spy MockWebApi, "getUserInfo"
-
-		MockDocStoreApi.docs[@doc_id] = @doc = 
-			_id: @doc_id
-			project_id: @project_id
-		sinon.spy MockDocStoreApi, "getAllDoc"
-
-		@updates = []
-		for i in [0..512+10]
-			@updates.push {
-				op: [{ i: "a", p: 0 }]
-				meta: { ts: @now + (i-2048) * @hours, user_id: @user_id }
-				v: 2 * i + 1
 			}
-			@updates.push {
-				op: [{ i: "b", p: 0 }]
-				meta: { ts: @now + (i-2048) * @hours + 10*@minutes, user_id: @user_id }
-				v: 2 * i + 2
-			}
-		TrackChangesApp.ensureRunning =>
-			TrackChangesClient.pushRawUpdates @project_id, @doc_id, @updates, (error) =>
-				throw error if error?
-				TrackChangesClient.flushDoc @project_id, @doc_id, (error) ->
-					throw error if error?
-					done()
-		return null
-
-	after (done) ->
-		MockWebApi.getUserInfo.restore()
-		db.docHistory.remove {project_id: ObjectId(@project_id)}, () =>
-			db.docHistoryIndex.remove {project_id: ObjectId(@project_id)}, () =>
-				TrackChangesClient.removeS3Doc @project_id, @doc_id, done
-
-	describe "archiving a doc's updates", ->
-		before (done) ->
-			TrackChangesClient.pushDocHistory @project_id, @doc_id, (error) ->
-				throw error if error?
-				done()
-			return null
-
-		it "should have one cached pack", (done) ->
-			db.docHistory.count { doc_id: ObjectId(@doc_id), expiresAt:{$exists:true}}, (error, count) ->
-				throw error if error?
-				count.should.equal 1
-				done()
-
-		it "should have one remaining pack after cache is expired", (done) ->
-			db.docHistory.remove {
-				doc_id: ObjectId(@doc_id),
+		};
+		sinon.spy(MockWebApi, "getProjectDetails");
+
+		MockWebApi.users[this.user_id] = (this.user = {
+			email: "user@sharelatex.com",
+			first_name: "Leo",
+			last_name: "Lion",
+			id: this.user_id
+		});
+		sinon.spy(MockWebApi, "getUserInfo");
+
+		MockDocStoreApi.docs[this.doc_id] = (this.doc = { 
+			_id: this.doc_id,
+			project_id: this.project_id
+		});
+		sinon.spy(MockDocStoreApi, "getAllDoc");
+
+		this.updates = [];
+		for (let i = 0, end = 512+10, asc = 0 <= end; asc ? i <= end : i >= end; asc ? i++ : i--) {
+			this.updates.push({
+				op: [{ i: "a", p: 0 }],
+				meta: { ts: this.now + ((i-2048) * this.hours), user_id: this.user_id },
+				v: (2 * i) + 1
+			});
+			this.updates.push({
+				op: [{ i: "b", p: 0 }],
+				meta: { ts: this.now + ((i-2048) * this.hours) + (10*this.minutes), user_id: this.user_id },
+				v: (2 * i) + 2
+			});
+		}
+		TrackChangesApp.ensureRunning(() => {
+			return TrackChangesClient.pushRawUpdates(this.project_id, this.doc_id, this.updates, error => {
+				if (error != null) { throw error; }
+				return TrackChangesClient.flushDoc(this.project_id, this.doc_id, function(error) {
+					if (error != null) { throw error; }
+					return done();
+				});
+			});
+		});
+		return null;
+	});
+
+	after(function(done) {
+		MockWebApi.getUserInfo.restore();
+		return db.docHistory.remove({project_id: ObjectId(this.project_id)}, () => {
+			return db.docHistoryIndex.remove({project_id: ObjectId(this.project_id)}, () => {
+				return TrackChangesClient.removeS3Doc(this.project_id, this.doc_id, done);
+			});
+		});
+	});
+
+	describe("archiving a doc's updates", function() {
+		before(function(done) {
+			TrackChangesClient.pushDocHistory(this.project_id, this.doc_id, function(error) {
+				if (error != null) { throw error; }
+				return done();
+			});
+			return null;
+		});
+
+		it("should have one cached pack", function(done) {
+			return db.docHistory.count({ doc_id: ObjectId(this.doc_id), expiresAt:{$exists:true}}, function(error, count) {
+				if (error != null) { throw error; }
+				count.should.equal(1);
+				return done();
+			});
+		});
+
+		it("should have one remaining pack after cache is expired", function(done) {
+			return db.docHistory.remove({
+				doc_id: ObjectId(this.doc_id),
 				expiresAt:{$exists:true}
-			}, (err, result) =>
-				throw error if error?
-				db.docHistory.count { doc_id: ObjectId(@doc_id)}, (error, count) ->
-					throw error if error?
-					count.should.equal 1
-					done()
-
-		it "should have a docHistoryIndex entry marked as inS3", (done) ->
-			db.docHistoryIndex.findOne { _id: ObjectId(@doc_id) }, (error, index) ->
-				throw error if error?
-				index.packs[0].inS3.should.equal true
-				done()
-
-		it "should have a docHistoryIndex entry with the last version", (done) ->
-			db.docHistoryIndex.findOne { _id: ObjectId(@doc_id) }, (error, index) ->
-				throw error if error?
-				index.packs[0].v_end.should.equal 1024
-				done()
-
-		it "should store 1024 doc changes in S3 in one pack", (done) ->
-			db.docHistoryIndex.findOne { _id: ObjectId(@doc_id) }, (error, index) =>
-				throw error if error?
-				pack_id = index.packs[0]._id
-				TrackChangesClient.getS3Doc @project_id, @doc_id, pack_id, (error, doc) =>
-					doc.n.should.equal 1024
-					doc.pack.length.should.equal 1024
-					done()
-
-	describe "unarchiving a doc's updates", ->
-		before (done) ->
-			TrackChangesClient.pullDocHistory @project_id, @doc_id, (error) ->
-				throw error if error?
-				done()
-			return null
-
-		it "should restore both packs", (done) ->
-			db.docHistory.count { doc_id: ObjectId(@doc_id) }, (error, count) ->
-				throw error if error?
-				count.should.equal 2
-				done()
+			}, (err, result) => {
+				if (typeof error !== 'undefined' && error !== null) { throw error; }
+				return db.docHistory.count({ doc_id: ObjectId(this.doc_id)}, function(error, count) {
+					if (error != null) { throw error; }
+					count.should.equal(1);
+					return done();
+				});
+			});
+		});
+
+		it("should have a docHistoryIndex entry marked as inS3", function(done) {
+			return db.docHistoryIndex.findOne({ _id: ObjectId(this.doc_id) }, function(error, index) {
+				if (error != null) { throw error; }
+				index.packs[0].inS3.should.equal(true);
+				return done();
+			});
+		});
+
+		it("should have a docHistoryIndex entry with the last version", function(done) {
+			return db.docHistoryIndex.findOne({ _id: ObjectId(this.doc_id) }, function(error, index) {
+				if (error != null) { throw error; }
+				index.packs[0].v_end.should.equal(1024);
+				return done();
+			});
+		});
+
+		return it("should store 1024 doc changes in S3 in one pack", function(done) {
+			return db.docHistoryIndex.findOne({ _id: ObjectId(this.doc_id) }, (error, index) => {
+				if (error != null) { throw error; }
+				const pack_id = index.packs[0]._id;
+				return TrackChangesClient.getS3Doc(this.project_id, this.doc_id, pack_id, (error, doc) => {
+					doc.n.should.equal(1024);
+					doc.pack.length.should.equal(1024);
+					return done();
+				});
+			});
+		});
+	});
+
+	return describe("unarchiving a doc's updates", function() {
+		before(function(done) {
+			TrackChangesClient.pullDocHistory(this.project_id, this.doc_id, function(error) {
+				if (error != null) { throw error; }
+				return done();
+			});
+			return null;
+		});
+
+		return it("should restore both packs", function(done) {
+			return db.docHistory.count({ doc_id: ObjectId(this.doc_id) }, function(error, count) {
+				if (error != null) { throw error; }
+				count.should.equal(2);
+				return done();
+			});
+		});
+	});
+});
+
+function __guard__(value, transform) {
+  return (typeof value !== 'undefined' && value !== null) ? transform(value) : undefined;
+}

+ 175 - 135
services/track-changes/test/acceptance/coffee/FlushingUpdatesTests.js

@@ -1,151 +1,191 @@
-sinon = require "sinon"
-chai = require("chai")
-chai.should()
-expect = chai.expect
-mongojs = require "../../../app/js/mongojs"
-ObjectId = mongojs.ObjectId
-Settings = require "settings-sharelatex"
-request = require "request"
-rclient = require("redis").createClient(Settings.redis.history) # Only works locally for now
-
-TrackChangesApp = require "./helpers/TrackChangesApp"
-TrackChangesClient = require "./helpers/TrackChangesClient"
-MockWebApi = require "./helpers/MockWebApi"
-
-describe "Flushing updates", ->
-	before (done)->
-		TrackChangesApp.ensureRunning done
-
-	describe "flushing a doc's updates", ->
-		before (done) ->
-			@project_id = ObjectId().toString()
-			@doc_id = ObjectId().toString()
-			@user_id = ObjectId().toString()
-			MockWebApi.projects[@project_id] = features: versioning: true
-
-			TrackChangesClient.pushRawUpdates @project_id, @doc_id, [{
-				op: [{ i: "f", p: 3 }]
-				meta: { ts: Date.now(), user_id: @user_id }
+/*
+ * decaffeinate suggestions:
+ * DS102: Remove unnecessary code created because of implicit returns
+ * DS207: Consider shorter variations of null checks
+ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
+ */
+const sinon = require("sinon");
+const chai = require("chai");
+chai.should();
+const { expect } = chai;
+const mongojs = require("../../../app/js/mongojs");
+const { ObjectId } = mongojs;
+const Settings = require("settings-sharelatex");
+const request = require("request");
+const rclient = require("redis").createClient(Settings.redis.history); // Only works locally for now
+
+const TrackChangesApp = require("./helpers/TrackChangesApp");
+const TrackChangesClient = require("./helpers/TrackChangesClient");
+const MockWebApi = require("./helpers/MockWebApi");
+
+describe("Flushing updates", function() {
+	before(done=> TrackChangesApp.ensureRunning(done));
+
+	describe("flushing a doc's updates", function() {
+		before(function(done) {
+			this.project_id = ObjectId().toString();
+			this.doc_id = ObjectId().toString();
+			this.user_id = ObjectId().toString();
+			MockWebApi.projects[this.project_id] = {features: {versioning: true}};
+
+			TrackChangesClient.pushRawUpdates(this.project_id, this.doc_id, [{
+				op: [{ i: "f", p: 3 }],
+				meta: { ts: Date.now(), user_id: this.user_id },
 				v: 3
-			}], (error) =>
-				throw error if error?
-				TrackChangesClient.flushDoc @project_id, @doc_id, (error) ->
-					throw error if error?
-					done()
-			return null
-
-		it "should flush the op into mongo", (done) ->
-			TrackChangesClient.getCompressedUpdates @doc_id, (error, updates) ->
-				expect(updates[0].pack[0].op).to.deep.equal [{
+			}], error => {
+				if (error != null) { throw error; }
+				return TrackChangesClient.flushDoc(this.project_id, this.doc_id, function(error) {
+					if (error != null) { throw error; }
+					return done();
+				});
+			});
+			return null;
+		});
+
+		return it("should flush the op into mongo", function(done) {
+			TrackChangesClient.getCompressedUpdates(this.doc_id, function(error, updates) {
+				expect(updates[0].pack[0].op).to.deep.equal([{
 					p: 3, i: "f"
-				}]
-				done()
-			return null
-
-	describe "flushing a project's updates", ->
-		describe "with versioning enabled", ->
-			before (done) ->
-				@project_id = ObjectId().toString()
-				@doc_id = ObjectId().toString()
-				@user_id = ObjectId().toString()
-
-				@weeks = 7 * 24 * 60 * 60 * 1000
-
-				MockWebApi.projects[@project_id] =
-					features:
+				}]);
+				return done();
+			});
+			return null;
+		});
+	});
+
+	return describe("flushing a project's updates", function() {
+		describe("with versioning enabled", function() {
+			before(function(done) {
+				this.project_id = ObjectId().toString();
+				this.doc_id = ObjectId().toString();
+				this.user_id = ObjectId().toString();
+
+				this.weeks = 7 * 24 * 60 * 60 * 1000;
+
+				MockWebApi.projects[this.project_id] = {
+					features: {
 						versioning: true
+					}
+				};
 
-				TrackChangesClient.pushRawUpdates @project_id, @doc_id, [{
-					op: [{ i: "g", p: 2 }]
-					meta: { ts: Date.now() - 2 * @weeks, user_id: @user_id }
+				TrackChangesClient.pushRawUpdates(this.project_id, this.doc_id, [{
+					op: [{ i: "g", p: 2 }],
+					meta: { ts: Date.now() - (2 * this.weeks), user_id: this.user_id },
 					v: 2
 				}, {
-					op: [{ i: "f", p: 3 }]
-					meta: { ts: Date.now(), user_id: @user_id }
+					op: [{ i: "f", p: 3 }],
+					meta: { ts: Date.now(), user_id: this.user_id },
 					v: 3
-				}], (error) =>
-					throw error if error?
-					TrackChangesClient.flushProject @project_id, (error) ->
-						throw error if error?
-						done()
-				return null
-
-			it "should not mark the updates for deletion", (done) ->
-				TrackChangesClient.getCompressedUpdates @doc_id, (error, updates) ->
-					expect(updates[0].expiresAt).to.not.exist
-					done()
-				return null
-
-			it "should preserve history forever", (done) ->
-				TrackChangesClient.getProjectMetaData @project_id, (error, project) ->
-					expect(project.preserveHistory).to.equal true
-					done()
-				return null
-
-		describe "without versioning enabled", ->
-			before (done) ->
-				@project_id = ObjectId().toString()
-				@doc_id = ObjectId().toString()
-				@user_id = ObjectId().toString()
-
-				@weeks = 7 * 24 * 60 * 60 * 1000
-
-				MockWebApi.projects[@project_id] =
-					features:
+				}], error => {
+					if (error != null) { throw error; }
+					return TrackChangesClient.flushProject(this.project_id, function(error) {
+						if (error != null) { throw error; }
+						return done();
+					});
+				});
+				return null;
+			});
+
+			it("should not mark the updates for deletion", function(done) {
+				TrackChangesClient.getCompressedUpdates(this.doc_id, function(error, updates) {
+					expect(updates[0].expiresAt).to.not.exist;
+					return done();
+				});
+				return null;
+			});
+
+			return it("should preserve history forever", function(done) {
+				TrackChangesClient.getProjectMetaData(this.project_id, function(error, project) {
+					expect(project.preserveHistory).to.equal(true);
+					return done();
+				});
+				return null;
+			});
+		});
+
+		describe("without versioning enabled", function() {
+			before(function(done) {
+				this.project_id = ObjectId().toString();
+				this.doc_id = ObjectId().toString();
+				this.user_id = ObjectId().toString();
+
+				this.weeks = 7 * 24 * 60 * 60 * 1000;
+
+				MockWebApi.projects[this.project_id] = {
+					features: {
 						versioning: false
+					}
+				};
 
-				TrackChangesClient.pushRawUpdates @project_id, @doc_id, [{
-					op: [{ i: "g", p: 2 }]
-					meta: { ts: Date.now() - 2 * @weeks, user_id: @user_id }
+				TrackChangesClient.pushRawUpdates(this.project_id, this.doc_id, [{
+					op: [{ i: "g", p: 2 }],
+					meta: { ts: Date.now() - (2 * this.weeks), user_id: this.user_id },
 					v: 2
 				}, {
-					op: [{ i: "f", p: 3 }]
-					meta: { ts: Date.now(), user_id: @user_id }
+					op: [{ i: "f", p: 3 }],
+					meta: { ts: Date.now(), user_id: this.user_id },
 					v: 3
-				}], (error) =>
-					throw error if error?
-					TrackChangesClient.flushProject @project_id, (error) ->
-						throw error if error?
-						done()
-				return null
-
-			it "should mark the updates for deletion", (done) ->
-				TrackChangesClient.getCompressedUpdates @doc_id, (error, updates) ->
-					expect(updates[0].expiresAt).to.exist
-					done()
-				return null
-
-		describe "without versioning enabled but with preserveHistory set to true", ->
-			before (done) ->
-				@project_id = ObjectId().toString()
-				@doc_id = ObjectId().toString()
-				@user_id = ObjectId().toString()
-
-				@weeks = 7 * 24 * 60 * 60 * 1000
-
-				MockWebApi.projects[@project_id] =
-					features:
+				}], error => {
+					if (error != null) { throw error; }
+					return TrackChangesClient.flushProject(this.project_id, function(error) {
+						if (error != null) { throw error; }
+						return done();
+					});
+				});
+				return null;
+			});
+
+			return it("should mark the updates for deletion", function(done) {
+				TrackChangesClient.getCompressedUpdates(this.doc_id, function(error, updates) {
+					expect(updates[0].expiresAt).to.exist;
+					return done();
+				});
+				return null;
+			});
+		});
+
+		return describe("without versioning enabled but with preserveHistory set to true", function() {
+			before(function(done) {
+				this.project_id = ObjectId().toString();
+				this.doc_id = ObjectId().toString();
+				this.user_id = ObjectId().toString();
+
+				this.weeks = 7 * 24 * 60 * 60 * 1000;
+
+				MockWebApi.projects[this.project_id] = {
+					features: {
 						versioning: false
-
-				TrackChangesClient.setPreserveHistoryForProject @project_id, (error) =>
-					throw error if error?
-					TrackChangesClient.pushRawUpdates @project_id, @doc_id, [{
-						op: [{ i: "g", p: 2 }]
-						meta: { ts: Date.now() - 2 * @weeks, user_id: @user_id }
+					}
+				};
+
+				TrackChangesClient.setPreserveHistoryForProject(this.project_id, error => {
+					if (error != null) { throw error; }
+					return TrackChangesClient.pushRawUpdates(this.project_id, this.doc_id, [{
+						op: [{ i: "g", p: 2 }],
+						meta: { ts: Date.now() - (2 * this.weeks), user_id: this.user_id },
 						v: 2
 					}, {
-						op: [{ i: "f", p: 3 }]
-						meta: { ts: Date.now(), user_id: @user_id }
+						op: [{ i: "f", p: 3 }],
+						meta: { ts: Date.now(), user_id: this.user_id },
 						v: 3
-					}], (error) =>
-						throw error if error?
-						TrackChangesClient.flushProject @project_id, (error) ->
-							throw error if error?
-							done()
-				return null
-
-			it "should not mark the updates for deletion", (done) ->
-				TrackChangesClient.getCompressedUpdates @doc_id, (error, updates) ->
-					expect(updates[0].expiresAt).to.not.exist
-					done()
-				return null
+					}], error => {
+						if (error != null) { throw error; }
+						return TrackChangesClient.flushProject(this.project_id, function(error) {
+							if (error != null) { throw error; }
+							return done();
+						});
+					});
+				});
+				return null;
+			});
+
+			return it("should not mark the updates for deletion", function(done) {
+				TrackChangesClient.getCompressedUpdates(this.doc_id, function(error, updates) {
+					expect(updates[0].expiresAt).to.not.exist;
+					return done();
+				});
+				return null;
+			});
+		});
+	});
+});

+ 82 - 66
services/track-changes/test/acceptance/coffee/GettingADiffTests.js

@@ -1,84 +1,100 @@
-sinon = require "sinon"
-chai = require("chai")
-chai.should()
-expect = chai.expect
-mongojs = require "../../../app/js/mongojs"
-db = mongojs.db
-ObjectId = mongojs.ObjectId
-Settings = require "settings-sharelatex"
+/*
+ * decaffeinate suggestions:
+ * DS102: Remove unnecessary code created because of implicit returns
+ * DS207: Consider shorter variations of null checks
+ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
+ */
+const sinon = require("sinon");
+const chai = require("chai");
+chai.should();
+const { expect } = chai;
+const mongojs = require("../../../app/js/mongojs");
+const { db } = mongojs;
+const { ObjectId } = mongojs;
+const Settings = require("settings-sharelatex");
 
-TrackChangesApp = require "./helpers/TrackChangesApp"
-TrackChangesClient = require "./helpers/TrackChangesClient"
-MockDocUpdaterApi = require "./helpers/MockDocUpdaterApi"
-MockWebApi = require "./helpers/MockWebApi"
+const TrackChangesApp = require("./helpers/TrackChangesApp");
+const TrackChangesClient = require("./helpers/TrackChangesClient");
+const MockDocUpdaterApi = require("./helpers/MockDocUpdaterApi");
+const MockWebApi = require("./helpers/MockWebApi");
 
-describe "Getting a diff", ->
+describe("Getting a diff", function() {
 
-	beforeEach (done) ->
-		sinon.spy MockDocUpdaterApi, "getDoc"
+	beforeEach(function(done) {
+		sinon.spy(MockDocUpdaterApi, "getDoc");
 
-		@now = Date.now()
-		@from = @now - 100000000
-		@to = @now
-		@user_id = ObjectId().toString()
-		@doc_id = ObjectId().toString()
-		@project_id = ObjectId().toString()
-		MockWebApi.projects[@project_id] = features: versioning: true
+		this.now = Date.now();
+		this.from = this.now - 100000000;
+		this.to = this.now;
+		this.user_id = ObjectId().toString();
+		this.doc_id = ObjectId().toString();
+		this.project_id = ObjectId().toString();
+		MockWebApi.projects[this.project_id] = {features: {versioning: true}};
 
-		MockWebApi.users[@user_id] = @user =
-			email: "user@sharelatex.com"
-			first_name: "Leo"
-			last_name: "Lion"
-			id: @user_id
-		sinon.spy MockWebApi, "getUserInfo"
+		MockWebApi.users[this.user_id] = (this.user = {
+			email: "user@sharelatex.com",
+			first_name: "Leo",
+			last_name: "Lion",
+			id: this.user_id
+		});
+		sinon.spy(MockWebApi, "getUserInfo");
 
-		twoMinutes = 2 * 60 * 1000
+		const twoMinutes = 2 * 60 * 1000;
 
-		@updates = [{
-			op: [{ i: "one ", p: 0 }]
-			meta: { ts: @from - twoMinutes, user_id: @user_id }
+		this.updates = [{
+			op: [{ i: "one ", p: 0 }],
+			meta: { ts: this.from - twoMinutes, user_id: this.user_id },
 			v: 3
 		}, {
-			op: [{ i: "two ", p: 4 }]
-			meta: { ts: @from + twoMinutes, user_id: @user_id }
-			v: @fromVersion = 4
+			op: [{ i: "two ", p: 4 }],
+			meta: { ts: this.from + twoMinutes, user_id: this.user_id },
+			v: (this.fromVersion = 4)
 		}, {
-			op: [{ i: "three ", p: 8 }]
-			meta: { ts: @to - twoMinutes, user_id: @user_id }
-			v: @toVersion = 5
+			op: [{ i: "three ", p: 8 }],
+			meta: { ts: this.to - twoMinutes, user_id: this.user_id },
+			v: (this.toVersion = 5)
 		}, {
-			op: [{ i: "four", p: 14 }]
-			meta: { ts: @to + twoMinutes, user_id: @user_id }
+			op: [{ i: "four", p: 14 }],
+			meta: { ts: this.to + twoMinutes, user_id: this.user_id },
 			v: 6
-		}]
-		@lines = ["one two three four"]
-		@expected_diff = [
-			{ u: "one " }
-			{ i: "two three ", meta: { start_ts: @from + twoMinutes, end_ts: @to - twoMinutes, user: @user } }
-		]
+		}];
+		this.lines = ["one two three four"];
+		this.expected_diff = [
+			{ u: "one " },
+			{ i: "two three ", meta: { start_ts: this.from + twoMinutes, end_ts: this.to - twoMinutes, user: this.user } }
+		];
 
-		MockDocUpdaterApi.docs[@doc_id] =
-			lines: @lines
+		MockDocUpdaterApi.docs[this.doc_id] = {
+			lines: this.lines,
 			version: 7
-		TrackChangesApp.ensureRunning =>
-			TrackChangesClient.pushRawUpdates @project_id, @doc_id, @updates, (error) =>
-				throw error if error?
-				TrackChangesClient.getDiff @project_id, @doc_id, @fromVersion, @toVersion, (error, diff) =>
-					throw error if error?
-					@diff = diff.diff
-					done()
-		return null
+		};
+		TrackChangesApp.ensureRunning(() => {
+			return TrackChangesClient.pushRawUpdates(this.project_id, this.doc_id, this.updates, error => {
+				if (error != null) { throw error; }
+				return TrackChangesClient.getDiff(this.project_id, this.doc_id, this.fromVersion, this.toVersion, (error, diff) => {
+					if (error != null) { throw error; }
+					this.diff = diff.diff;
+					return done();
+				});
+			});
+		});
+		return null;
+	});
 
-	afterEach () ->
-		MockDocUpdaterApi.getDoc.restore()
-		MockWebApi.getUserInfo.restore()
-		return null
+	afterEach(function() {
+		MockDocUpdaterApi.getDoc.restore();
+		MockWebApi.getUserInfo.restore();
+		return null;
+	});
 
-	it "should return the diff", ->
-		expect(@diff).to.deep.equal @expected_diff
+	it("should return the diff", function() {
+		return expect(this.diff).to.deep.equal(this.expected_diff);
+	});
 
-	it "should get the doc from the doc updater", ->
+	return it("should get the doc from the doc updater", function() {
 		MockDocUpdaterApi.getDoc
-			.calledWith(@project_id, @doc_id)
-			.should.equal true
-		return null
+			.calledWith(this.project_id, this.doc_id)
+			.should.equal(true);
+		return null;
+	});
+});

+ 140 - 109
services/track-changes/test/acceptance/coffee/GettingUpdatesTests.js

@@ -1,126 +1,157 @@
-sinon = require "sinon"
-chai = require("chai")
-chai.should()
-expect = chai.expect
-mongojs = require "../../../app/js/mongojs"
-db = mongojs.db
-ObjectId = mongojs.ObjectId
-Settings = require "settings-sharelatex"
+/*
+ * decaffeinate suggestions:
+ * DS102: Remove unnecessary code created because of implicit returns
+ * DS207: Consider shorter variations of null checks
+ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
+ */
+const sinon = require("sinon");
+const chai = require("chai");
+chai.should();
+const { expect } = chai;
+const mongojs = require("../../../app/js/mongojs");
+const { db } = mongojs;
+const { ObjectId } = mongojs;
+const Settings = require("settings-sharelatex");
 
-TrackChangesApp = require "./helpers/TrackChangesApp"
-TrackChangesClient = require "./helpers/TrackChangesClient"
-MockWebApi = require "./helpers/MockWebApi"
+const TrackChangesApp = require("./helpers/TrackChangesApp");
+const TrackChangesClient = require("./helpers/TrackChangesClient");
+const MockWebApi = require("./helpers/MockWebApi");
 
-describe "Getting updates", ->
-	before (done) ->
-		@now = Date.now()
-		@to = @now
-		@user_id = ObjectId().toString()
-		@deleted_user_id = 'deleted_user'
-		@doc_id = ObjectId().toString()
-		@project_id = ObjectId().toString()
+describe("Getting updates", function() {
+	before(function(done) {
+		this.now = Date.now();
+		this.to = this.now;
+		this.user_id = ObjectId().toString();
+		this.deleted_user_id = 'deleted_user';
+		this.doc_id = ObjectId().toString();
+		this.project_id = ObjectId().toString();
 
-		@minutes = 60 * 1000
-		@hours = 60 * @minutes
+		this.minutes = 60 * 1000;
+		this.hours = 60 * this.minutes;
 
-		MockWebApi.projects[@project_id] =
-			features:
+		MockWebApi.projects[this.project_id] = {
+			features: {
 				versioning: true
+			}
+		};
 
-		MockWebApi.users[@user_id] = @user =
-			email: "user@sharelatex.com"
-			first_name: "Leo"
-			last_name: "Lion"
-			id: @user_id
-		sinon.spy MockWebApi, "getUserInfo"
+		MockWebApi.users[this.user_id] = (this.user = {
+			email: "user@sharelatex.com",
+			first_name: "Leo",
+			last_name: "Lion",
+			id: this.user_id
+		});
+		sinon.spy(MockWebApi, "getUserInfo");
 
-		@updates = []
-		for i in [0..9]
-			@updates.push {
-				op: [{ i: "a", p: 0 }]
-				meta: { ts: @now - (9 - i) * @hours - 2 * @minutes, user_id: @user_id }
-				v: 2 * i + 1
-			}
-			@updates.push {
-				op: [{ i: "b", p: 0 }]
-				meta: { ts: @now - (9 - i) * @hours, user_id: @user_id }
-				v: 2 * i + 2
-			}
-		@updates[0].meta.user_id = @deleted_user_id
+		this.updates = [];
+		for (let i = 0; i <= 9; i++) {
+			this.updates.push({
+				op: [{ i: "a", p: 0 }],
+				meta: { ts: this.now - ((9 - i) * this.hours) - (2 * this.minutes), user_id: this.user_id },
+				v: (2 * i) + 1
+			});
+			this.updates.push({
+				op: [{ i: "b", p: 0 }],
+				meta: { ts: this.now - ((9 - i) * this.hours), user_id: this.user_id },
+				v: (2 * i) + 2
+			});
+		}
+		this.updates[0].meta.user_id = this.deleted_user_id;
 
-		TrackChangesApp.ensureRunning =>
-			TrackChangesClient.pushRawUpdates @project_id, @doc_id, @updates, (error) =>
-				throw error if error?
-				done()
-		return null
+		TrackChangesApp.ensureRunning(() => {
+			return TrackChangesClient.pushRawUpdates(this.project_id, this.doc_id, this.updates, error => {
+				if (error != null) { throw error; }
+				return done();
+			});
+		});
+		return null;
+	});
 
-	after: () ->
-		MockWebApi.getUserInfo.restore()
-		return null
+	({
+		after() {
+			MockWebApi.getUserInfo.restore();
+			return null;
+		}
+	});
 
-	describe "getting updates up to the limit", ->
-		before (done) ->
-			TrackChangesClient.getUpdates @project_id, { before: @to + 1, min_count: 3 }, (error, body) =>
-				throw error if error?
-				@updates = body.updates
-				done()
-			return null
+	describe("getting updates up to the limit", function() {
+		before(function(done) {
+			TrackChangesClient.getUpdates(this.project_id, { before: this.to + 1, min_count: 3 }, (error, body) => {
+				if (error != null) { throw error; }
+				this.updates = body.updates;
+				return done();
+			});
+			return null;
+		});
 
-		it "should fetch the user details from the web api", ->
-			MockWebApi.getUserInfo
-				.calledWith(@user_id)
-				.should.equal true
+		it("should fetch the user details from the web api", function() {
+			return MockWebApi.getUserInfo
+				.calledWith(this.user_id)
+				.should.equal(true);
+		});
 
-		it "should return at least the min_count number of summarized updates", ->
-			docs1 = {}
-			docs1[@doc_id] = toV: 20, fromV: 19
-			docs2 = {}
-			docs2[@doc_id] = toV: 18, fromV: 17
-			docs3 = {}
-			docs3[@doc_id] = toV: 16, fromV: 15
-			expect(@updates.slice(0,3)).to.deep.equal [{
-				docs: docs1
-				meta:
-					start_ts: @to - 2 * @minutes
-					end_ts: @to
-					users: [@user]
+		return it("should return at least the min_count number of summarized updates", function() {
+			const docs1 = {};
+			docs1[this.doc_id] = {toV: 20, fromV: 19};
+			const docs2 = {};
+			docs2[this.doc_id] = {toV: 18, fromV: 17};
+			const docs3 = {};
+			docs3[this.doc_id] = {toV: 16, fromV: 15};
+			return expect(this.updates.slice(0,3)).to.deep.equal([{
+				docs: docs1,
+				meta: {
+					start_ts: this.to - (2 * this.minutes),
+					end_ts: this.to,
+					users: [this.user]
+				}
 			}, {
-				docs: docs2
-				meta:
-					start_ts: @to - 1 * @hours - 2 * @minutes
-					end_ts: @to - 1 * @hours
-					users: [@user]
+				docs: docs2,
+				meta: {
+					start_ts: this.to - (1 * this.hours) - (2 * this.minutes),
+					end_ts: this.to - (1 * this.hours),
+					users: [this.user]
+				}
 			}, {
-				docs: docs3
-				meta:
-					start_ts: @to - 2 * @hours - 2 * @minutes
-					end_ts: @to - 2 * @hours
-					users: [@user]
-			}]
+				docs: docs3,
+				meta: {
+					start_ts: this.to - (2 * this.hours) - (2 * this.minutes),
+					end_ts: this.to - (2 * this.hours),
+					users: [this.user]
+				}
+			}]);
+	});
+});
 
-	describe "getting updates beyond the end of the database", ->
-		before (done) ->
-			TrackChangesClient.getUpdates @project_id, { before: @to - 8 * @hours + 1, min_count: 30 }, (error, body) =>
-				throw error if error?
-				@updates = body.updates
-				done()
-			return null
+	return describe("getting updates beyond the end of the database", function() {
+		before(function(done) {
+			TrackChangesClient.getUpdates(this.project_id, { before: (this.to - (8 * this.hours)) + 1, min_count: 30 }, (error, body) => {
+				if (error != null) { throw error; }
+				this.updates = body.updates;
+				return done();
+			});
+			return null;
+		});
 
-		it "should return as many updates as it can", ->
-			docs1 = {}
-			docs1[@doc_id] = toV: 4, fromV: 3
-			docs2 = {}
-			docs2[@doc_id] = toV: 2, fromV: 1
-			expect(@updates).to.deep.equal [{
-				docs: docs1
-				meta:
-					start_ts: @to - 8 * @hours - 2 * @minutes
-					end_ts: @to - 8 * @hours
-					users: [@user]
+		return it("should return as many updates as it can", function() {
+			const docs1 = {};
+			docs1[this.doc_id] = {toV: 4, fromV: 3};
+			const docs2 = {};
+			docs2[this.doc_id] = {toV: 2, fromV: 1};
+			return expect(this.updates).to.deep.equal([{
+				docs: docs1,
+				meta: {
+					start_ts: this.to - (8 * this.hours) - (2 * this.minutes),
+					end_ts: this.to - (8 * this.hours),
+					users: [this.user]
+				}
 			}, {
-				docs: docs2
-				meta:
-					start_ts: @to - 9 * @hours - 2 * @minutes
-					end_ts: @to - 9 * @hours
-					users: [@user, null]
-			}]
+				docs: docs2,
+				meta: {
+					start_ts: this.to - (9 * this.hours) - (2 * this.minutes),
+					end_ts: this.to - (9 * this.hours),
+					users: [this.user, null]
+				}
+			}]);
+	});
+});
+});

+ 49 - 34
services/track-changes/test/acceptance/coffee/LockManagerTests.js

@@ -1,39 +1,54 @@
-sinon = require "sinon"
-chai = require("chai")
-chai.should()
-expect = chai.expect
-mongojs = require "../../../app/js/mongojs"
-ObjectId = mongojs.ObjectId
-Settings = require "settings-sharelatex"
-LockManager = require "../../../app/js/LockManager"
-rclient = require("redis").createClient(Settings.redis.history) # Only works locally for now
-TrackChangesApp = require "./helpers/TrackChangesApp"
+/*
+ * decaffeinate suggestions:
+ * DS102: Remove unnecessary code created because of implicit returns
+ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
+ */
+const sinon = require("sinon");
+const chai = require("chai");
+chai.should();
+const { expect } = chai;
+const mongojs = require("../../../app/js/mongojs");
+const { ObjectId } = mongojs;
+const Settings = require("settings-sharelatex");
+const LockManager = require("../../../app/js/LockManager");
+const rclient = require("redis").createClient(Settings.redis.history); // Only works locally for now
+const TrackChangesApp = require("./helpers/TrackChangesApp");
 
-describe "Locking document", ->
+describe("Locking document", function() {
 
-	before (done)->
-		TrackChangesApp.ensureRunning done
-		return null
+	before(function(done){
+		TrackChangesApp.ensureRunning(done);
+		return null;
+	});
 		
-	describe "when the lock has expired in redis", ->
-		before (done) ->
-			LockManager.LOCK_TTL = 1 # second
-			LockManager.runWithLock "doc123", (releaseA) =>
-				# we create a lock A and allow it to expire in redis
-				setTimeout () ->
-					# now we create a new lock B and try to release A
-					LockManager.runWithLock "doc123", (releaseB) =>
-						releaseA()  # try to release lock A to see if it wipes out lock B
-					, (error) ->
-						# we never release lock B so nothing should happen here
-				, 1500 # enough time to wait until the lock has expired
-			, (error) ->
-				# we get here after trying to release lock A
+	return describe("when the lock has expired in redis", function() {
+		before(function(done) {
+			LockManager.LOCK_TTL = 1; // second
+			LockManager.runWithLock("doc123", releaseA => {
+				// we create a lock A and allow it to expire in redis
+				return setTimeout(() =>
+					// now we create a new lock B and try to release A
+					LockManager.runWithLock("doc123", releaseB => {
+						return releaseA();
+					}  // try to release lock A to see if it wipes out lock B
+					, function(error) {})
+				
+						// we never release lock B so nothing should happen here
+				, 1500);
+			} // enough time to wait until the lock has expired
+			, error =>
+				// we get here after trying to release lock A
 				done()
-			return null
+			);
+			return null;
+		});
 
-		it "the new lock should not be removed by the expired locker", (done) ->
-			LockManager.checkLock "doc123", (err, isFree) ->
-					expect(isFree).to.equal false
-					done()
-			return null
+		return it("the new lock should not be removed by the expired locker", function(done) {
+			LockManager.checkLock("doc123", function(err, isFree) {
+					expect(isFree).to.equal(false);
+					return done();
+			});
+			return null;
+		});
+	});
+});

+ 70 - 55
services/track-changes/test/acceptance/coffee/RestoringVersions.js

@@ -1,74 +1,89 @@
-sinon = require "sinon"
-chai = require("chai")
-chai.should()
-expect = chai.expect
-mongojs = require "../../../app/js/mongojs"
-db = mongojs.db
-ObjectId = mongojs.ObjectId
-Settings = require "settings-sharelatex"
+/*
+ * decaffeinate suggestions:
+ * DS102: Remove unnecessary code created because of implicit returns
+ * DS207: Consider shorter variations of null checks
+ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
+ */
+const sinon = require("sinon");
+const chai = require("chai");
+chai.should();
+const { expect } = chai;
+const mongojs = require("../../../app/js/mongojs");
+const { db } = mongojs;
+const { ObjectId } = mongojs;
+const Settings = require("settings-sharelatex");
 
-TrackChangesApp = require "./helpers/TrackChangesApp"
-TrackChangesClient = require "./helpers/TrackChangesClient"
-MockDocUpdaterApi = require "./helpers/MockDocUpdaterApi"
-MockWebApi = require "./helpers/MockWebApi"
+const TrackChangesApp = require("./helpers/TrackChangesApp");
+const TrackChangesClient = require("./helpers/TrackChangesClient");
+const MockDocUpdaterApi = require("./helpers/MockDocUpdaterApi");
+const MockWebApi = require("./helpers/MockWebApi");
 
-describe "Restoring a version", ->
-	before (done) ->
-		sinon.spy MockDocUpdaterApi, "setDoc"
+describe("Restoring a version", function() {
+	before(function(done) {
+		sinon.spy(MockDocUpdaterApi, "setDoc");
 
-		@now = Date.now()
-		@user_id = ObjectId().toString()
-		@doc_id = ObjectId().toString()
-		@project_id = ObjectId().toString()
-		MockWebApi.projects[@project_id] = features: versioning: true
+		this.now = Date.now();
+		this.user_id = ObjectId().toString();
+		this.doc_id = ObjectId().toString();
+		this.project_id = ObjectId().toString();
+		MockWebApi.projects[this.project_id] = {features: {versioning: true}};
 		
-		minutes = 60 * 1000
+		const minutes = 60 * 1000;
 
-		@updates = [{
-			op: [{ i: "one ", p: 0 }]
-			meta: { ts: @now - 6 * minutes, user_id: @user_id }
+		this.updates = [{
+			op: [{ i: "one ", p: 0 }],
+			meta: { ts: this.now - (6 * minutes), user_id: this.user_id },
 			v: 3
 		}, {
-			op: [{ i: "two ", p: 4 }]
-			meta: { ts: @now - 4 * minutes, user_id: @user_id }
+			op: [{ i: "two ", p: 4 }],
+			meta: { ts: this.now - (4 * minutes), user_id: this.user_id },
 			v: 4
 		}, {
-			op: [{ i: "three ", p: 8 }]
-			meta: { ts: @now - 2 * minutes, user_id: @user_id }
+			op: [{ i: "three ", p: 8 }],
+			meta: { ts: this.now - (2 * minutes), user_id: this.user_id },
 			v: 5
 		}, {
-			op: [{ i: "four", p: 14 }]
-			meta: { ts: @now, user_id: @user_id }
+			op: [{ i: "four", p: 14 }],
+			meta: { ts: this.now, user_id: this.user_id },
 			v: 6
-		}]
-		@lines = ["one two three four"]
-		@restored_lines = ["one two "]
-		@beforeVersion = 5
+		}];
+		this.lines = ["one two three four"];
+		this.restored_lines = ["one two "];
+		this.beforeVersion = 5;
 
-		MockWebApi.users[@user_id] = @user =
-			email: "user@sharelatex.com"
-			first_name: "Leo"
-			last_name: "Lion"
-			id: @user_id
+		MockWebApi.users[this.user_id] = (this.user = {
+			email: "user@sharelatex.com",
+			first_name: "Leo",
+			last_name: "Lion",
+			id: this.user_id
+		});
 
-		MockDocUpdaterApi.docs[@doc_id] =
-			lines: @lines
+		MockDocUpdaterApi.docs[this.doc_id] = {
+			lines: this.lines,
 			version: 7
+		};
 
-		TrackChangesApp.ensureRunning =>
-			TrackChangesClient.pushRawUpdates @project_id, @doc_id, @updates, (error) =>
-				throw error if error?
-				TrackChangesClient.restoreDoc @project_id, @doc_id, @beforeVersion, @user_id, (error) =>
-					throw error if error?
-					done()
-		return null
+		TrackChangesApp.ensureRunning(() => {
+			return TrackChangesClient.pushRawUpdates(this.project_id, this.doc_id, this.updates, error => {
+				if (error != null) { throw error; }
+				return TrackChangesClient.restoreDoc(this.project_id, this.doc_id, this.beforeVersion, this.user_id, error => {
+					if (error != null) { throw error; }
+					return done();
+				});
+			});
+		});
+		return null;
+	});
 
-	after () ->
-		MockDocUpdaterApi.setDoc.restore()
-		return null
+	after(function() {
+		MockDocUpdaterApi.setDoc.restore();
+		return null;
+	});
 
-	it "should set the doc in the doc updater", ->
+	return it("should set the doc in the doc updater", function() {
 		MockDocUpdaterApi.setDoc
-			.calledWith(@project_id, @doc_id, @restored_lines, @user_id, true)
-			.should.equal true
-		return null
+			.calledWith(this.project_id, this.doc_id, this.restored_lines, this.user_id, true)
+			.should.equal(true);
+		return null;
+	});
+});

+ 37 - 21
services/track-changes/test/acceptance/coffee/helpers/MockDocStoreApi.js

@@ -1,27 +1,43 @@
-express = require("express")
-app = express()
+/*
+ * decaffeinate suggestions:
+ * DS102: Remove unnecessary code created because of implicit returns
+ * DS207: Consider shorter variations of null checks
+ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
+ */
+let MockDocUpdaterApi;
+const express = require("express");
+const app = express();
 
-module.exports = MockDocUpdaterApi =
-	docs: {}
+module.exports = (MockDocUpdaterApi = {
+	docs: {},
 
-	getAllDoc: (project_id, callback = (error) ->) ->
-		callback null, @docs
+	getAllDoc(project_id, callback) {
+		if (callback == null) { callback = function(error) {}; }
+		return callback(null, this.docs);
+	},
 
-	run: () ->
-		app.get "/project/:project_id/doc", (req, res, next) =>
-			@getAllDoc req.params.project_id, (error, docs) ->
-				if error?
-					res.send 500
-				if !docs?
-					res.send 404
-				else
-					res.send JSON.stringify docs
+	run() {
+		app.get("/project/:project_id/doc", (req, res, next) => {
+			return this.getAllDoc(req.params.project_id, function(error, docs) {
+				if (error != null) {
+					res.send(500);
+				}
+				if ((docs == null)) {
+					return res.send(404);
+				} else {
+					return res.send(JSON.stringify(docs));
+				}
+			});
+		});
 
-		app.listen 3016, (error) ->
-			throw error if error?
-		.on "error", (error) ->
-			console.error "error starting MockDocStoreApi:", error.message
-			process.exit(1)
+		return app.listen(3016, function(error) {
+			if (error != null) { throw error; }
+	}).on("error", function(error) {
+			console.error("error starting MockDocStoreApi:", error.message);
+			return process.exit(1);
+		});
+	}
+});
 
-MockDocUpdaterApi.run()
+MockDocUpdaterApi.run();
 

+ 60 - 39
services/track-changes/test/acceptance/coffee/helpers/MockDocUpdaterApi.js

@@ -1,40 +1,61 @@
-express = require("express")
-app = express()
-
-module.exports = MockDocUpdaterApi =
-	docs: {}
-
-	getDoc: (project_id, doc_id, callback = (error) ->) ->
-		callback null, @docs[doc_id]
-
-	setDoc: (project_id, doc_id, lines, user_id, undoing, callback = (error) ->) ->
-		@docs[doc_id] ||= {}
-		@docs[doc_id].lines = lines
-		callback()
-
-	run: () ->
-		app.get "/project/:project_id/doc/:doc_id", (req, res, next) =>
-			@getDoc req.params.project_id, req.params.doc_id, (error, doc) ->
-				if error?
-					res.send 500
-				if !doc?
-					res.send 404
-				else
-					res.send JSON.stringify doc
-
-		app.post "/project/:project_id/doc/:doc_id", express.bodyParser(), (req, res, next) =>
-			@setDoc req.params.project_id, req.params.doc_id, req.body.lines, req.body.user_id, req.body.undoing, (errr, doc) ->
-				if error?
-					res.send 500
-				else
-					res.send 204
-
-		app.listen 3003, (error) ->
-			throw error if error?
-		.on "error", (error) ->
-			console.error "error starting MockDocUpdaterApi:", error.message
-			process.exit(1)
-
-
-MockDocUpdaterApi.run()
+/*
+ * decaffeinate suggestions:
+ * DS102: Remove unnecessary code created because of implicit returns
+ * DS207: Consider shorter variations of null checks
+ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
+ */
+let MockDocUpdaterApi;
+const express = require("express");
+const app = express();
+
+module.exports = (MockDocUpdaterApi = {
+	docs: {},
+
+	getDoc(project_id, doc_id, callback) {
+		if (callback == null) { callback = function(error) {}; }
+		return callback(null, this.docs[doc_id]);
+	},
+
+	setDoc(project_id, doc_id, lines, user_id, undoing, callback) {
+		if (callback == null) { callback = function(error) {}; }
+		if (!this.docs[doc_id]) { this.docs[doc_id] = {}; }
+		this.docs[doc_id].lines = lines;
+		return callback();
+	},
+
+	run() {
+		app.get("/project/:project_id/doc/:doc_id", (req, res, next) => {
+			return this.getDoc(req.params.project_id, req.params.doc_id, function(error, doc) {
+				if (error != null) {
+					res.send(500);
+				}
+				if ((doc == null)) {
+					return res.send(404);
+				} else {
+					return res.send(JSON.stringify(doc));
+				}
+			});
+		});
+
+		app.post("/project/:project_id/doc/:doc_id", express.bodyParser(), (req, res, next) => {
+			return this.setDoc(req.params.project_id, req.params.doc_id, req.body.lines, req.body.user_id, req.body.undoing, function(errr, doc) {
+				if (typeof error !== 'undefined' && error !== null) {
+					return res.send(500);
+				} else {
+					return res.send(204);
+				}
+			});
+		});
+
+		return app.listen(3003, function(error) {
+			if (error != null) { throw error; }
+	}).on("error", function(error) {
+			console.error("error starting MockDocUpdaterApi:", error.message);
+			return process.exit(1);
+		});
+	}
+});
+
+
+MockDocUpdaterApi.run();
 

+ 62 - 40
services/track-changes/test/acceptance/coffee/helpers/MockWebApi.js

@@ -1,41 +1,63 @@
-express = require("express")
-app = express()
-
-module.exports = MockWebApi =
-	users: {}
-
-	projects: {}
-
-	getUserInfo: (user_id, callback = (error) ->) ->
-		callback null, @users[user_id] or null
-
-	getProjectDetails: (project_id, callback = (error, project) ->) ->
-		callback null, @projects[project_id]
-
-	run: () ->
-		app.get "/user/:user_id/personal_info", (req, res, next) =>
-			@getUserInfo req.params.user_id, (error, user) ->
-				if error?
-					res.send 500
-				if !user?
-					res.send 404
-				else
-					res.send JSON.stringify user
-
-		app.get "/project/:project_id/details", (req, res, next) =>
-			@getProjectDetails req.params.project_id, (error, project) ->
-				if error?
-					res.send 500
-				if !project?
-					res.send 404
-				else
-					res.send JSON.stringify project
-
-		app.listen 3000, (error) ->
-			throw error if error?
-		.on "error", (error) ->
-			console.error "error starting MockWebApiServer:", error.message
-			process.exit(1)
-
-MockWebApi.run()
+/*
+ * decaffeinate suggestions:
+ * DS102: Remove unnecessary code created because of implicit returns
+ * DS207: Consider shorter variations of null checks
+ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
+ */
+let MockWebApi;
+const express = require("express");
+const app = express();
+
+module.exports = (MockWebApi = {
+	users: {},
+
+	projects: {},
+
+	getUserInfo(user_id, callback) {
+		if (callback == null) { callback = function(error) {}; }
+		return callback(null, this.users[user_id] || null);
+	},
+
+	getProjectDetails(project_id, callback) {
+		if (callback == null) { callback = function(error, project) {}; }
+		return callback(null, this.projects[project_id]);
+	},
+
+	run() {
+		app.get("/user/:user_id/personal_info", (req, res, next) => {
+			return this.getUserInfo(req.params.user_id, function(error, user) {
+				if (error != null) {
+					res.send(500);
+				}
+				if ((user == null)) {
+					return res.send(404);
+				} else {
+					return res.send(JSON.stringify(user));
+				}
+			});
+		});
+
+		app.get("/project/:project_id/details", (req, res, next) => {
+			return this.getProjectDetails(req.params.project_id, function(error, project) {
+				if (error != null) {
+					res.send(500);
+				}
+				if ((project == null)) {
+					return res.send(404);
+				} else {
+					return res.send(JSON.stringify(project));
+				}
+			});
+		});
+
+		return app.listen(3000, function(error) {
+			if (error != null) { throw error; }
+	}).on("error", function(error) {
+			console.error("error starting MockWebApiServer:", error.message);
+			return process.exit(1);
+		});
+	}
+});
+
+MockWebApi.run();
 

+ 44 - 22
services/track-changes/test/acceptance/coffee/helpers/TrackChangesApp.js

@@ -1,24 +1,46 @@
-app = require('../../../../app')
-require("logger-sharelatex")
-logger = require("logger-sharelatex")
-Settings = require("settings-sharelatex")
+/*
+ * decaffeinate suggestions:
+ * DS101: Remove unnecessary use of Array.from
+ * DS102: Remove unnecessary code created because of implicit returns
+ * DS103: Rewrite code to no longer use __guard__
+ * DS205: Consider reworking code to avoid use of IIFEs
+ * DS207: Consider shorter variations of null checks
+ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
+ */
+const app = require('../../../../app');
+require("logger-sharelatex");
+const logger = require("logger-sharelatex");
+const Settings = require("settings-sharelatex");
 
-module.exports =
-	running: false
-	initing: false
-	callbacks: []
-	ensureRunning: (callback = (error) ->) ->
-		if @running
-			return callback()
-		else if @initing
-			@callbacks.push callback
-		else
-			@initing = true
-			@callbacks.push callback
-			app.listen Settings.internal?.trackchanges?.port, "localhost", (error) => 
-				throw error if error?
-				@running = true
-				logger.log("track changes running in dev mode")
+module.exports = {
+	running: false,
+	initing: false,
+	callbacks: [],
+	ensureRunning(callback) {
+		if (callback == null) { callback = function(error) {}; }
+		if (this.running) {
+			return callback();
+		} else if (this.initing) {
+			return this.callbacks.push(callback);
+		} else {
+			this.initing = true;
+			this.callbacks.push(callback);
+			return app.listen(__guard__(Settings.internal != null ? Settings.internal.trackchanges : undefined, x => x.port), "localhost", error => { 
+				if (error != null) { throw error; }
+				this.running = true;
+				logger.log("track changes running in dev mode");
 
-				for callback in @callbacks
-					callback()
+				return (() => {
+					const result = [];
+					for (callback of Array.from(this.callbacks)) {
+						result.push(callback());
+					}
+					return result;
+				})();
+			});
+		}
+	}
+};
+function __guard__(value, transform) {
+  return (typeof value !== 'undefined' && value !== null) ? transform(value) : undefined;
+}

+ 192 - 134
services/track-changes/test/acceptance/coffee/helpers/TrackChangesClient.js

@@ -1,144 +1,202 @@
-async = require 'async'
-zlib = require 'zlib'
-request = require "request"
-Settings = require "settings-sharelatex"
-rclient = require("redis-sharelatex").createClient(Settings.redis.history) # Only works locally for now
-Keys = Settings.redis.history.key_schema
-{db, ObjectId} = require "../../../../app/js/mongojs"
-
-aws = require "aws-sdk"
-s3 = new aws.S3(
-	accessKeyId: Settings.trackchanges.s3.key
-	secretAccessKey: Settings.trackchanges.s3.secret
-	endpoint: Settings.trackchanges.s3.endpoint
+/*
+ * decaffeinate suggestions:
+ * DS101: Remove unnecessary use of Array.from
+ * DS102: Remove unnecessary code created because of implicit returns
+ * DS207: Consider shorter variations of null checks
+ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
+ */
+let TrackChangesClient;
+const async = require('async');
+const zlib = require('zlib');
+const request = require("request");
+const Settings = require("settings-sharelatex");
+const rclient = require("redis-sharelatex").createClient(Settings.redis.history); // Only works locally for now
+const Keys = Settings.redis.history.key_schema;
+const {db, ObjectId} = require("../../../../app/js/mongojs");
+
+const aws = require("aws-sdk");
+const s3 = new aws.S3({
+	accessKeyId: Settings.trackchanges.s3.key,
+	secretAccessKey: Settings.trackchanges.s3.secret,
+	endpoint: Settings.trackchanges.s3.endpoint,
 	s3ForcePathStyle: Settings.trackchanges.s3.pathStyle
-)
-S3_BUCKET = Settings.trackchanges.stores.doc_history
-
-module.exports = TrackChangesClient =
-	flushAndGetCompressedUpdates: (project_id, doc_id, callback = (error, updates) ->) ->
-		TrackChangesClient.flushDoc project_id, doc_id, (error) ->
-			return callback(error) if error?
-			TrackChangesClient.getCompressedUpdates doc_id, callback
-
-	flushDoc: (project_id, doc_id, callback = (error) ->) ->
-		request.post {
-			url: "http://localhost:3015/project/#{project_id}/doc/#{doc_id}/flush"
-		}, (error, response, body) =>
-			response.statusCode.should.equal 204
-			callback(error)
-
-	flushProject: (project_id, callback = (error) ->) ->
-		request.post {
-			url: "http://localhost:3015/project/#{project_id}/flush"
-		}, (error, response, body) =>
-			response.statusCode.should.equal 204
-			callback(error)
-
-	getCompressedUpdates: (doc_id, callback = (error, updates) ->) ->
-		db.docHistory
-			.find(doc_id: ObjectId(doc_id))
-			.sort("meta.end_ts": 1)
-			.toArray callback
-
-	getProjectMetaData: (project_id, callback = (error, updates) ->) ->
-		db.projectHistoryMetaData
-			.find {
+});
+const S3_BUCKET = Settings.trackchanges.stores.doc_history;
+
+module.exports = (TrackChangesClient = {
+	flushAndGetCompressedUpdates(project_id, doc_id, callback) {
+		if (callback == null) { callback = function(error, updates) {}; }
+		return TrackChangesClient.flushDoc(project_id, doc_id, function(error) {
+			if (error != null) { return callback(error); }
+			return TrackChangesClient.getCompressedUpdates(doc_id, callback);
+		});
+	},
+
+	flushDoc(project_id, doc_id, callback) {
+		if (callback == null) { callback = function(error) {}; }
+		return request.post({
+			url: `http://localhost:3015/project/${project_id}/doc/${doc_id}/flush`
+		}, (error, response, body) => {
+			response.statusCode.should.equal(204);
+			return callback(error);
+		});
+	},
+
+	flushProject(project_id, callback) {
+		if (callback == null) { callback = function(error) {}; }
+		return request.post({
+			url: `http://localhost:3015/project/${project_id}/flush`
+		}, (error, response, body) => {
+			response.statusCode.should.equal(204);
+			return callback(error);
+		});
+	},
+
+	getCompressedUpdates(doc_id, callback) {
+		if (callback == null) { callback = function(error, updates) {}; }
+		return db.docHistory
+			.find({doc_id: ObjectId(doc_id)})
+			.sort({"meta.end_ts": 1})
+			.toArray(callback);
+	},
+
+	getProjectMetaData(project_id, callback) {
+		if (callback == null) { callback = function(error, updates) {}; }
+		return db.projectHistoryMetaData
+			.find({
 				project_id: ObjectId(project_id)
 			},
-			(error, projects) ->
-				callback error, projects[0]
+			(error, projects) => callback(error, projects[0]));
+	},
 
-	setPreserveHistoryForProject: (project_id, callback = (error) ->) ->
-		db.projectHistoryMetaData.update {
+	setPreserveHistoryForProject(project_id, callback) {
+		if (callback == null) { callback = function(error) {}; }
+		return db.projectHistoryMetaData.update({
 			project_id: ObjectId(project_id)
 			}, {
 				$set: { preserveHistory: true }
 			}, {
 				upsert: true
-			}, callback
-
-	pushRawUpdates: (project_id, doc_id, updates, callback = (error) ->) ->
-		rclient.sadd Keys.docsWithHistoryOps({project_id}), doc_id, (error) ->
-			return callback(error) if error?
-			rclient.rpush Keys.uncompressedHistoryOps({doc_id}), (JSON.stringify(u) for u in updates)..., callback
-
-	getDiff: (project_id, doc_id, from, to, callback = (error, diff) ->) ->
-		request.get {
-			url: "http://localhost:3015/project/#{project_id}/doc/#{doc_id}/diff?from=#{from}&to=#{to}"
-		}, (error, response, body) =>
-			response.statusCode.should.equal 200
-			callback null, JSON.parse(body)
-
-	getUpdates: (project_id, options, callback = (error, body) ->) ->
-		request.get {
-			url: "http://localhost:3015/project/#{project_id}/updates?before=#{options.before}&min_count=#{options.min_count}"
-		}, (error, response, body) =>
-			response.statusCode.should.equal 200
-			callback null, JSON.parse(body)
-
-	restoreDoc: (project_id, doc_id, version, user_id, callback = (error) ->) ->
-		request.post {
-			url: "http://localhost:3015/project/#{project_id}/doc/#{doc_id}/version/#{version}/restore"
-			headers:
+			}, callback);
+	},
+
+	pushRawUpdates(project_id, doc_id, updates, callback) {
+		if (callback == null) { callback = function(error) {}; }
+		return rclient.sadd(Keys.docsWithHistoryOps({project_id}), doc_id, function(error) {
+			if (error != null) { return callback(error); }
+			return rclient.rpush(Keys.uncompressedHistoryOps({doc_id}), ...Array.from(((Array.from(updates).map((u) => JSON.stringify(u))))), callback);
+		});
+	},
+
+	getDiff(project_id, doc_id, from, to, callback) {
+		if (callback == null) { callback = function(error, diff) {}; }
+		return request.get({
+			url: `http://localhost:3015/project/${project_id}/doc/${doc_id}/diff?from=${from}&to=${to}`
+		}, (error, response, body) => {
+			response.statusCode.should.equal(200);
+			return callback(null, JSON.parse(body));
+		});
+	},
+
+	getUpdates(project_id, options, callback) {
+		if (callback == null) { callback = function(error, body) {}; }
+		return request.get({
+			url: `http://localhost:3015/project/${project_id}/updates?before=${options.before}&min_count=${options.min_count}`
+		}, (error, response, body) => {
+			response.statusCode.should.equal(200);
+			return callback(null, JSON.parse(body));
+		});
+	},
+
+	restoreDoc(project_id, doc_id, version, user_id, callback) {
+		if (callback == null) { callback = function(error) {}; }
+		return request.post({
+			url: `http://localhost:3015/project/${project_id}/doc/${doc_id}/version/${version}/restore`,
+			headers: {
 				"X-User-Id": user_id
-		}, (error, response, body) =>
-			response.statusCode.should.equal 204
-			callback null
-
-	pushDocHistory: (project_id, doc_id, callback = (error) ->) ->
-		request.post {
-			url: "http://localhost:3015/project/#{project_id}/doc/#{doc_id}/push"
-		}, (error, response, body) =>
-			response.statusCode.should.equal 204
-			callback(error)
-
-	pullDocHistory: (project_id, doc_id, callback = (error) ->) ->
-		request.post {
-			url: "http://localhost:3015/project/#{project_id}/doc/#{doc_id}/pull"
-		}, (error, response, body) =>
-			response.statusCode.should.equal 204
-			callback(error)
-
-	waitForS3: (done, retries=42) ->
-		if !Settings.trackchanges.s3.endpoint
-			return done()
-
-		request.get "#{Settings.trackchanges.s3.endpoint}/", (err, res) ->
-			if res && res.statusCode < 500
-				return done()
-
-			if retries == 0
-				return done(err or new Error("s3 returned #{res.statusCode}"))
-
-			setTimeout () ->
-				TrackChangesClient.waitForS3(done, --retries)
-			, 1000
-
-	getS3Doc: (project_id, doc_id, pack_id, callback = (error, body) ->) ->
-		params =
-			Bucket: S3_BUCKET
-			Key: "#{project_id}/changes-#{doc_id}/pack-#{pack_id}"
-
-		s3.getObject params, (error, data) ->
-			return callback(error) if error?
-			body = data.Body
-			return callback(new Error("empty response from s3")) if not body?
-			zlib.gunzip body, (err, result) ->
-				return callback(err) if err?
-				callback(null, JSON.parse(result.toString()))
-
-	removeS3Doc: (project_id, doc_id, callback = (error, res, body) ->) ->
-		params =
-			Bucket: S3_BUCKET
-			Prefix: "#{project_id}/changes-#{doc_id}"
-
-		s3.listObjects params, (error, data) ->
-			return callback(error) if error?
-
-			params =
-				Bucket: S3_BUCKET
-				Delete:
-					Objects: data.Contents.map((s3object) -> {Key: s3object.Key})
-
-			s3.deleteObjects params, callback
+			}
+		}, (error, response, body) => {
+			response.statusCode.should.equal(204);
+			return callback(null);
+		});
+	},
+
+	pushDocHistory(project_id, doc_id, callback) {
+		if (callback == null) { callback = function(error) {}; }
+		return request.post({
+			url: `http://localhost:3015/project/${project_id}/doc/${doc_id}/push`
+		}, (error, response, body) => {
+			response.statusCode.should.equal(204);
+			return callback(error);
+		});
+	},
+
+	pullDocHistory(project_id, doc_id, callback) {
+		if (callback == null) { callback = function(error) {}; }
+		return request.post({
+			url: `http://localhost:3015/project/${project_id}/doc/${doc_id}/pull`
+		}, (error, response, body) => {
+			response.statusCode.should.equal(204);
+			return callback(error);
+		});
+	},
+
+	waitForS3(done, retries) {
+		if (retries == null) { retries = 42; }
+		if (!Settings.trackchanges.s3.endpoint) {
+			return done();
+		}
+
+		return request.get(`${Settings.trackchanges.s3.endpoint}/`, function(err, res) {
+			if (res && (res.statusCode < 500)) {
+				return done();
+			}
+
+			if (retries === 0) {
+				return done(err || new Error(`s3 returned ${res.statusCode}`));
+			}
+
+			return setTimeout(() => TrackChangesClient.waitForS3(done, --retries)
+			, 1000);
+		});
+	},
+
+	getS3Doc(project_id, doc_id, pack_id, callback) {
+		if (callback == null) { callback = function(error, body) {}; }
+		const params = {
+			Bucket: S3_BUCKET,
+			Key: `${project_id}/changes-${doc_id}/pack-${pack_id}`
+		};
+
+		return s3.getObject(params, function(error, data) {
+			if (error != null) { return callback(error); }
+			const body = data.Body;
+			if ((body == null)) { return callback(new Error("empty response from s3")); }
+			return zlib.gunzip(body, function(err, result) {
+				if (err != null) { return callback(err); }
+				return callback(null, JSON.parse(result.toString()));
+			});
+		});
+	},
+
+	removeS3Doc(project_id, doc_id, callback) {
+		if (callback == null) { callback = function(error, res, body) {}; }
+		let params = {
+			Bucket: S3_BUCKET,
+			Prefix: `${project_id}/changes-${doc_id}`
+		};
+
+		return s3.listObjects(params, function(error, data) {
+			if (error != null) { return callback(error); }
+
+			params = {
+				Bucket: S3_BUCKET,
+				Delete: {
+					Objects: data.Contents.map(s3object => ({Key: s3object.Key}))
+				}
+			};
+
+			return s3.deleteObjects(params, callback);
+		});
+	}
+});