/* * decaffeinate suggestions: * DS102: Remove unnecessary code created because of implicit returns * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ const chai = require('chai'); const { expect } = chai; const should = chai.should(); const sinon = require("sinon"); const modulePath = "../../../app/js/RoomManager.js"; const SandboxedModule = require('sandboxed-module'); describe('RoomManager', function() { beforeEach(function() { this.project_id = "project-id-123"; this.doc_id = "doc-id-456"; this.other_doc_id = "doc-id-789"; this.client = {namespace: {name: ''}, id: "first-client"}; this.RoomManager = SandboxedModule.require(modulePath, { requires: { "settings-sharelatex": (this.settings = {}), "logger-sharelatex": (this.logger = { log: sinon.stub(), warn: sinon.stub(), error: sinon.stub() }), "metrics-sharelatex": (this.metrics = { gauge: sinon.stub() }) } }); this.RoomManager._clientsInRoom = sinon.stub(); this.RoomManager._clientAlreadyInRoom = sinon.stub(); this.RoomEvents = this.RoomManager.eventSource(); sinon.spy(this.RoomEvents, 'emit'); return sinon.spy(this.RoomEvents, 'once'); }); describe("emitOnCompletion", () => describe("when a subscribe errors", function() { afterEach(function() { return process.removeListener("unhandledRejection", this.onUnhandled); }); beforeEach(function(done) { this.onUnhandled = error => { this.unhandledError = error; return done(new Error(`unhandledRejection: ${error.message}`)); }; process.on("unhandledRejection", this.onUnhandled); let reject = undefined; const subscribePromise = new Promise((_, r) => reject = r); const promises = [subscribePromise]; const eventName = "project-subscribed-123"; this.RoomEvents.once(eventName, () => setTimeout(done, 100)); this.RoomManager.emitOnCompletion(promises, eventName); return setTimeout(() => reject(new Error("subscribe failed"))); }); return it("should keep going", function() { return expect(this.unhandledError).to.not.exist; }); })); describe("joinProject", function() { describe("when the project room is empty", function() { beforeEach(function(done) { this.RoomManager._clientsInRoom .withArgs(this.client, this.project_id) .onFirstCall().returns(0); this.client.join = sinon.stub(); this.callback = sinon.stub(); this.RoomEvents.on('project-active', id => { return setTimeout(() => { return this.RoomEvents.emit(`project-subscribed-${id}`); } , 100); }); return this.RoomManager.joinProject(this.client, this.project_id, err => { this.callback(err); return done(); }); }); it("should emit a 'project-active' event with the id", function() { return this.RoomEvents.emit.calledWithExactly('project-active', this.project_id).should.equal(true); }); it("should listen for the 'project-subscribed-id' event", function() { return this.RoomEvents.once.calledWith(`project-subscribed-${this.project_id}`).should.equal(true); }); return it("should join the room using the id", function() { return this.client.join.calledWithExactly(this.project_id).should.equal(true); }); }); return describe("when there are other clients in the project room", function() { beforeEach(function() { this.RoomManager._clientsInRoom .withArgs(this.client, this.project_id) .onFirstCall().returns(123) .onSecondCall().returns(124); this.client.join = sinon.stub(); return this.RoomManager.joinProject(this.client, this.project_id); }); it("should join the room using the id", function() { return this.client.join.called.should.equal(true); }); return it("should not emit any events", function() { return this.RoomEvents.emit.called.should.equal(false); }); }); }); describe("joinDoc", function() { describe("when the doc room is empty", function() { beforeEach(function(done) { this.RoomManager._clientsInRoom .withArgs(this.client, this.doc_id) .onFirstCall().returns(0); this.client.join = sinon.stub(); this.callback = sinon.stub(); this.RoomEvents.on('doc-active', id => { return setTimeout(() => { return this.RoomEvents.emit(`doc-subscribed-${id}`); } , 100); }); return this.RoomManager.joinDoc(this.client, this.doc_id, err => { this.callback(err); return done(); }); }); it("should emit a 'doc-active' event with the id", function() { return this.RoomEvents.emit.calledWithExactly('doc-active', this.doc_id).should.equal(true); }); it("should listen for the 'doc-subscribed-id' event", function() { return this.RoomEvents.once.calledWith(`doc-subscribed-${this.doc_id}`).should.equal(true); }); return it("should join the room using the id", function() { return this.client.join.calledWithExactly(this.doc_id).should.equal(true); }); }); return describe("when there are other clients in the doc room", function() { beforeEach(function() { this.RoomManager._clientsInRoom .withArgs(this.client, this.doc_id) .onFirstCall().returns(123) .onSecondCall().returns(124); this.client.join = sinon.stub(); return this.RoomManager.joinDoc(this.client, this.doc_id); }); it("should join the room using the id", function() { return this.client.join.called.should.equal(true); }); return it("should not emit any events", function() { return this.RoomEvents.emit.called.should.equal(false); }); }); }); describe("leaveDoc", function() { describe("when doc room will be empty after this client has left", function() { beforeEach(function() { this.RoomManager._clientAlreadyInRoom .withArgs(this.client, this.doc_id) .returns(true); this.RoomManager._clientsInRoom .withArgs(this.client, this.doc_id) .onCall(0).returns(0); this.client.leave = sinon.stub(); return this.RoomManager.leaveDoc(this.client, this.doc_id); }); it("should leave the room using the id", function() { return this.client.leave.calledWithExactly(this.doc_id).should.equal(true); }); return it("should emit a 'doc-empty' event with the id", function() { return this.RoomEvents.emit.calledWithExactly('doc-empty', this.doc_id).should.equal(true); }); }); describe("when there are other clients in the doc room", function() { beforeEach(function() { this.RoomManager._clientAlreadyInRoom .withArgs(this.client, this.doc_id) .returns(true); this.RoomManager._clientsInRoom .withArgs(this.client, this.doc_id) .onCall(0).returns(123); this.client.leave = sinon.stub(); return this.RoomManager.leaveDoc(this.client, this.doc_id); }); it("should leave the room using the id", function() { return this.client.leave.calledWithExactly(this.doc_id).should.equal(true); }); return it("should not emit any events", function() { return this.RoomEvents.emit.called.should.equal(false); }); }); return describe("when the client is not in the doc room", function() { beforeEach(function() { this.RoomManager._clientAlreadyInRoom .withArgs(this.client, this.doc_id) .returns(false); this.RoomManager._clientsInRoom .withArgs(this.client, this.doc_id) .onCall(0).returns(0); this.client.leave = sinon.stub(); return this.RoomManager.leaveDoc(this.client, this.doc_id); }); it("should not leave the room", function() { return this.client.leave.called.should.equal(false); }); return it("should not emit any events", function() { return this.RoomEvents.emit.called.should.equal(false); }); }); }); return describe("leaveProjectAndDocs", () => describe("when the client is connected to the project and multiple docs", function() { beforeEach(function() { this.RoomManager._roomsClientIsIn = sinon.stub().returns([this.project_id, this.doc_id, this.other_doc_id]); this.client.join = sinon.stub(); return this.client.leave = sinon.stub(); }); describe("when this is the only client connected", function() { beforeEach(function(done) { // first call is for the join, // second for the leave this.RoomManager._clientsInRoom .withArgs(this.client, this.doc_id) .onCall(0).returns(0) .onCall(1).returns(0); this.RoomManager._clientsInRoom .withArgs(this.client, this.other_doc_id) .onCall(0).returns(0) .onCall(1).returns(0); this.RoomManager._clientsInRoom .withArgs(this.client, this.project_id) .onCall(0).returns(0) .onCall(1).returns(0); this.RoomManager._clientAlreadyInRoom .withArgs(this.client, this.doc_id) .returns(true) .withArgs(this.client, this.other_doc_id) .returns(true) .withArgs(this.client, this.project_id) .returns(true); this.RoomEvents.on('project-active', id => { return setTimeout(() => { return this.RoomEvents.emit(`project-subscribed-${id}`); } , 100); }); this.RoomEvents.on('doc-active', id => { return setTimeout(() => { return this.RoomEvents.emit(`doc-subscribed-${id}`); } , 100); }); // put the client in the rooms return this.RoomManager.joinProject(this.client, this.project_id, () => { return this.RoomManager.joinDoc(this.client, this.doc_id, () => { return this.RoomManager.joinDoc(this.client, this.other_doc_id, () => { // now leave the project this.RoomManager.leaveProjectAndDocs(this.client); return done(); }); }); }); }); it("should leave all the docs", function() { this.client.leave.calledWithExactly(this.doc_id).should.equal(true); return this.client.leave.calledWithExactly(this.other_doc_id).should.equal(true); }); it("should leave the project", function() { return this.client.leave.calledWithExactly(this.project_id).should.equal(true); }); it("should emit a 'doc-empty' event with the id for each doc", function() { this.RoomEvents.emit.calledWithExactly('doc-empty', this.doc_id).should.equal(true); return this.RoomEvents.emit.calledWithExactly('doc-empty', this.other_doc_id).should.equal(true); }); return it("should emit a 'project-empty' event with the id for the project", function() { return this.RoomEvents.emit.calledWithExactly('project-empty', this.project_id).should.equal(true); }); }); return describe("when other clients are still connected", function() { beforeEach(function() { this.RoomManager._clientsInRoom .withArgs(this.client, this.doc_id) .onFirstCall().returns(123) .onSecondCall().returns(122); this.RoomManager._clientsInRoom .withArgs(this.client, this.other_doc_id) .onFirstCall().returns(123) .onSecondCall().returns(122); this.RoomManager._clientsInRoom .withArgs(this.client, this.project_id) .onFirstCall().returns(123) .onSecondCall().returns(122); this.RoomManager._clientAlreadyInRoom .withArgs(this.client, this.doc_id) .returns(true) .withArgs(this.client, this.other_doc_id) .returns(true) .withArgs(this.client, this.project_id) .returns(true); return this.RoomManager.leaveProjectAndDocs(this.client); }); it("should leave all the docs", function() { this.client.leave.calledWithExactly(this.doc_id).should.equal(true); return this.client.leave.calledWithExactly(this.other_doc_id).should.equal(true); }); it("should leave the project", function() { return this.client.leave.calledWithExactly(this.project_id).should.equal(true); }); return it("should not emit any events", function() { return this.RoomEvents.emit.called.should.equal(false); }); }); })); });