mirror of
https://github.com/overleaf/overleaf.git
synced 2024-12-27 08:31:43 +00:00
251 lines
7.4 KiB
CoffeeScript
251 lines
7.4 KiB
CoffeeScript
define [
|
|
"libs/chai"
|
|
"editor/ShareJsDoc"
|
|
"libs/sharejs"
|
|
"libs/sinon"
|
|
], (
|
|
chai
|
|
ShareJsDoc
|
|
ShareJs
|
|
) ->
|
|
should = chai.should()
|
|
expect = chai.expect
|
|
|
|
describe "ShareJsDoc", ->
|
|
beforeEach ->
|
|
@lines = ["hello", "world"]
|
|
@snapshot = @lines.join("\n")
|
|
@doc_id = "mock-doc-id"
|
|
@version = 42
|
|
|
|
socket: @socket =
|
|
socket:
|
|
sessionid: @session_id = "mock-session-id"
|
|
connected: true
|
|
emit: sinon.stub()
|
|
|
|
sinon.spy ShareJs.Doc::, "_onMessage"
|
|
sinon.spy ShareJs.Doc::, "on"
|
|
sinon.spy ShareJs, "Doc"
|
|
|
|
afterEach ->
|
|
ShareJs.Doc::_onMessage.restore()
|
|
ShareJs.Doc::on.restore()
|
|
ShareJs.Doc.restore()
|
|
|
|
describe "Creating a ShareJsDoc", ->
|
|
beforeEach ->
|
|
@shareJsDoc = new ShareJsDoc(@doc_id, @lines, @version, @socket)
|
|
|
|
it "should create a new ShareJs.Doc instance", ->
|
|
expect(@shareJsDoc._doc instanceof ShareJs.Doc).to.be.true
|
|
|
|
it "should set the ShareJs doc connection", ->
|
|
ShareJs.Doc
|
|
.calledWith(@shareJsDoc.connection)
|
|
.should.equal true
|
|
|
|
it "should set the ShareJs doc name", ->
|
|
ShareJs.Doc
|
|
.calledWith(sinon.match.any, @doc_id)
|
|
.should.equal true
|
|
|
|
it "should set the type of the ShareJs doc to 'text'", ->
|
|
ShareJs.Doc
|
|
.calledWith(sinon.match.any, sinon.match.any, type: "text")
|
|
.should.equal true
|
|
|
|
it "should open the ShareJs doc so that it is in an active state", ->
|
|
ShareJs.Doc::_onMessage
|
|
.calledWith({
|
|
open: true
|
|
snapshot: @snapshot
|
|
v: @version
|
|
})
|
|
.should.equal true
|
|
|
|
it "should bind to the ShareJs doc events", ->
|
|
ShareJs.Doc::on.calledWith("change").should.equal true
|
|
ShareJs.Doc::on.calledWith("acknowledge").should.equal true
|
|
ShareJs.Doc::on.calledWith("remoteop").should.equal true
|
|
|
|
describe "Sending an op", ->
|
|
describe "when the server responds", ->
|
|
beforeEach (done) ->
|
|
@shareJsDoc = new ShareJsDoc(@doc_id, @lines, @version, @socket)
|
|
@shareJsDoc.submitOp @op = [p: 5, i: "foo"], () -> done()
|
|
|
|
# Send the acknowledgement so that the callback is called
|
|
setTimeout () =>
|
|
@shareJsDoc.processUpdateFromServer {
|
|
v: @version
|
|
doc: @doc_id
|
|
}
|
|
, 10
|
|
|
|
|
|
it "should send the op to the server", ->
|
|
@socket.emit
|
|
.calledWith("applyOtUpdate", @doc_id, {
|
|
doc: @doc_id,
|
|
op: @op
|
|
v: @version
|
|
})
|
|
.should.equal true
|
|
|
|
it "should update the document snapshot", ->
|
|
@shareJsDoc.getSnapshot().should.equal "hellofoo\nworld"
|
|
|
|
describe "when the server does not respond", ->
|
|
beforeEach (done) ->
|
|
@shareJsDoc = new ShareJsDoc(@doc_id, @lines, @version, @socket)
|
|
sinon.spy @shareJsDoc, "trigger"
|
|
@shareJsDoc.INFLIGHT_OP_TIMEOUT = 50
|
|
@shareJsDoc.submitOp @op = [p: 5, i: "foo"]
|
|
|
|
setTimeout () ->
|
|
done()
|
|
, 100
|
|
|
|
it "should trigger an error", ->
|
|
@shareJsDoc.trigger
|
|
.calledWith("error", "Doc op was not acknowledged in time")
|
|
.should.equal true
|
|
|
|
describe "clearInflightAndPendingOps", ->
|
|
beforeEach ->
|
|
@shareJsDoc = new ShareJsDoc(@doc_id, @lines, @version, @socket)
|
|
@shareJsDoc._doc.inflightOp = "mock-op-1"
|
|
@shareJsDoc._doc.inflightCallbacks = ["mock-callback-1"]
|
|
@shareJsDoc._doc.pendingOp = "mock-op-2"
|
|
@shareJsDoc._doc.pendingCallbacks = ["mock-callback-2"]
|
|
|
|
@shareJsDoc.clearInflightAndPendingOps()
|
|
|
|
it "should clear any inflight or pendings ops", ->
|
|
expect(@shareJsDoc._doc.inflightOp).to.be.null
|
|
@shareJsDoc._doc.inflightCallbacks.should.deep.equal []
|
|
expect(@shareJsDoc._doc.pendingOp).to.be.null
|
|
@shareJsDoc._doc.pendingCallbacks.should.deep.equal []
|
|
|
|
describe "flushPendingOps", ->
|
|
beforeEach ->
|
|
@shareJsDoc = new ShareJsDoc(@doc_id, @lines, @version, @socket)
|
|
@shareJsDoc._doc.flush = sinon.stub()
|
|
@shareJsDoc.flushPendingOps()
|
|
|
|
it "should call _doc.flush", ->
|
|
@shareJsDoc._doc.flush.called.should.equal true
|
|
|
|
describe "updateConnectionState", ->
|
|
beforeEach ->
|
|
@shareJsDoc = new ShareJsDoc(@doc_id, @lines, @version, @socket)
|
|
@shareJsDoc._doc._connectionStateChanged = sinon.stub()
|
|
@shareJsDoc._doc.autoOpen = true
|
|
@socket.socket.sessionid = "new-connection-id"
|
|
|
|
@shareJsDoc.updateConnectionState "mock-state"
|
|
|
|
it "should set autoOpen to false so that ShareJs doesn't try to send an open message", ->
|
|
@shareJsDoc._doc.autoOpen.should.equal false
|
|
|
|
it "should update the connection state", ->
|
|
@shareJsDoc.connection.state.should.equal "mock-state"
|
|
|
|
it "should notify the ShareJs doc of the state change", ->
|
|
@shareJsDoc._doc._connectionStateChanged
|
|
.calledWith("mock-state")
|
|
.should.equal true
|
|
|
|
it "should set the connection id to the latest socket id", ->
|
|
@shareJsDoc.connection.id.should.equal "new-connection-id"
|
|
|
|
describe "hasBufferedOps", ->
|
|
describe "with inflight ops", ->
|
|
beforeEach ->
|
|
@shareJsDoc = new ShareJsDoc(@doc_id, @lines, @version, @socket)
|
|
@shareJsDoc._doc.inflightOp = "mock-op-1"
|
|
|
|
it "should return true", ->
|
|
@shareJsDoc.hasBufferedOps().should.equal true
|
|
|
|
describe "with pending ops", ->
|
|
beforeEach ->
|
|
@shareJsDoc = new ShareJsDoc(@doc_id, @lines, @version, @socket)
|
|
@shareJsDoc._doc.pendingOp = "mock-op-1"
|
|
|
|
it "should return true", ->
|
|
@shareJsDoc.hasBufferedOps().should.equal true
|
|
|
|
describe "with no buffered ops", ->
|
|
beforeEach ->
|
|
@shareJsDoc = new ShareJsDoc(@doc_id, @lines, @version, @socket)
|
|
|
|
it "should return false", ->
|
|
@shareJsDoc.hasBufferedOps().should.equal false
|
|
|
|
describe "processUpdateFromServer", ->
|
|
describe "successfully", ->
|
|
beforeEach ->
|
|
@shareJsDoc = new ShareJsDoc(@doc_id, @lines, @version, @socket)
|
|
@shareJsDoc._doc._onMessage = sinon.stub()
|
|
@shareJsDoc.processUpdateFromServer "mock-message"
|
|
|
|
it "should pass the message onto the ShareJs Doc", ->
|
|
@shareJsDoc._doc._onMessage
|
|
.calledWith( "mock-message" )
|
|
.should.equal true
|
|
|
|
describe "with an error", ->
|
|
beforeEach ->
|
|
@shareJsDoc = new ShareJsDoc(@doc_id, @lines, @version, @socket)
|
|
sinon.spy @shareJsDoc, "trigger"
|
|
@shareJsDoc._doc._onMessage = sinon.stub().throws(@error = {message: "Mock error"})
|
|
@shareJsDoc.processUpdateFromServer "mock-message"
|
|
|
|
it "should trigger the error handler", ->
|
|
@shareJsDoc.trigger
|
|
.calledWith("error", @error)
|
|
.should.equal true
|
|
|
|
describe "with an external update", ->
|
|
beforeEach ->
|
|
@shareJsDoc = new ShareJsDoc(@doc_id, @lines, @version, @socket)
|
|
@shareJsDoc._doc._onMessage = sinon.stub()
|
|
sinon.spy @shareJsDoc, "trigger"
|
|
@shareJsDoc.processUpdateFromServer { op: "mock-op", meta: { type: "external" } }
|
|
|
|
it "should trigger an externalUpdate event", ->
|
|
@shareJsDoc.trigger
|
|
.calledWith("externalUpdate")
|
|
.should.equal true
|
|
|
|
|
|
describe "catchUp", ->
|
|
beforeEach ->
|
|
@shareJsDoc = new ShareJsDoc(@doc_id, @lines, @version, @socket)
|
|
sinon.stub @shareJsDoc, "processUpdateFromServer", () ->
|
|
@_doc.version++
|
|
|
|
@shareJsDoc.catchUp [{
|
|
ops: ["mock-op-1"]
|
|
}, {
|
|
ops: ["mock-op-2"]
|
|
}]
|
|
|
|
it "should apply each update", ->
|
|
@shareJsDoc.processUpdateFromServer
|
|
.calledWith({
|
|
doc: @doc_id
|
|
v: @version
|
|
ops: ["mock-op-1"]
|
|
})
|
|
.should.equal true
|
|
|
|
@shareJsDoc.processUpdateFromServer
|
|
.calledWith({
|
|
doc: @doc_id
|
|
v: @version + 1
|
|
ops: ["mock-op-2"]
|
|
})
|
|
.should.equal true
|