ShareJsDocTests.coffee 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. define [
  2. "libs/chai"
  3. "editor/ShareJsDoc"
  4. "libs/sharejs"
  5. "libs/sinon"
  6. ], (
  7. chai
  8. ShareJsDoc
  9. ShareJs
  10. ) ->
  11. should = chai.should()
  12. expect = chai.expect
  13. describe "ShareJsDoc", ->
  14. beforeEach ->
  15. @lines = ["hello", "world"]
  16. @snapshot = @lines.join("\n")
  17. @doc_id = "mock-doc-id"
  18. @version = 42
  19. socket: @socket =
  20. socket:
  21. sessionid: @session_id = "mock-session-id"
  22. connected: true
  23. emit: sinon.stub()
  24. sinon.spy ShareJs.Doc::, "_onMessage"
  25. sinon.spy ShareJs.Doc::, "on"
  26. sinon.spy ShareJs, "Doc"
  27. afterEach ->
  28. ShareJs.Doc::_onMessage.restore()
  29. ShareJs.Doc::on.restore()
  30. ShareJs.Doc.restore()
  31. describe "Creating a ShareJsDoc", ->
  32. beforeEach ->
  33. @shareJsDoc = new ShareJsDoc(@doc_id, @lines, @version, @socket)
  34. it "should create a new ShareJs.Doc instance", ->
  35. expect(@shareJsDoc._doc instanceof ShareJs.Doc).to.be.true
  36. it "should set the ShareJs doc connection", ->
  37. ShareJs.Doc
  38. .calledWith(@shareJsDoc.connection)
  39. .should.equal true
  40. it "should set the ShareJs doc name", ->
  41. ShareJs.Doc
  42. .calledWith(sinon.match.any, @doc_id)
  43. .should.equal true
  44. it "should set the type of the ShareJs doc to 'text'", ->
  45. ShareJs.Doc
  46. .calledWith(sinon.match.any, sinon.match.any, type: "text")
  47. .should.equal true
  48. it "should open the ShareJs doc so that it is in an active state", ->
  49. ShareJs.Doc::_onMessage
  50. .calledWith({
  51. open: true
  52. snapshot: @snapshot
  53. v: @version
  54. })
  55. .should.equal true
  56. it "should bind to the ShareJs doc events", ->
  57. ShareJs.Doc::on.calledWith("change").should.equal true
  58. ShareJs.Doc::on.calledWith("acknowledge").should.equal true
  59. ShareJs.Doc::on.calledWith("remoteop").should.equal true
  60. describe "Sending an op", ->
  61. describe "when the server responds", ->
  62. beforeEach (done) ->
  63. @shareJsDoc = new ShareJsDoc(@doc_id, @lines, @version, @socket)
  64. @shareJsDoc.submitOp @op = [p: 5, i: "foo"], () -> done()
  65. # Send the acknowledgement so that the callback is called
  66. setTimeout () =>
  67. @shareJsDoc.processUpdateFromServer {
  68. v: @version
  69. doc: @doc_id
  70. }
  71. , 10
  72. it "should send the op to the server", ->
  73. @socket.emit
  74. .calledWith("applyOtUpdate", @doc_id, {
  75. doc: @doc_id,
  76. op: @op
  77. v: @version
  78. })
  79. .should.equal true
  80. it "should update the document snapshot", ->
  81. @shareJsDoc.getSnapshot().should.equal "hellofoo\nworld"
  82. describe "when the server does not respond", ->
  83. beforeEach (done) ->
  84. @shareJsDoc = new ShareJsDoc(@doc_id, @lines, @version, @socket)
  85. sinon.spy @shareJsDoc, "trigger"
  86. @shareJsDoc.INFLIGHT_OP_TIMEOUT = 50
  87. @shareJsDoc.submitOp @op = [p: 5, i: "foo"]
  88. setTimeout () ->
  89. done()
  90. , 100
  91. it "should trigger an error", ->
  92. @shareJsDoc.trigger
  93. .calledWith("error", "Doc op was not acknowledged in time")
  94. .should.equal true
  95. describe "clearInflightAndPendingOps", ->
  96. beforeEach ->
  97. @shareJsDoc = new ShareJsDoc(@doc_id, @lines, @version, @socket)
  98. @shareJsDoc._doc.inflightOp = "mock-op-1"
  99. @shareJsDoc._doc.inflightCallbacks = ["mock-callback-1"]
  100. @shareJsDoc._doc.pendingOp = "mock-op-2"
  101. @shareJsDoc._doc.pendingCallbacks = ["mock-callback-2"]
  102. @shareJsDoc.clearInflightAndPendingOps()
  103. it "should clear any inflight or pendings ops", ->
  104. expect(@shareJsDoc._doc.inflightOp).to.be.null
  105. @shareJsDoc._doc.inflightCallbacks.should.deep.equal []
  106. expect(@shareJsDoc._doc.pendingOp).to.be.null
  107. @shareJsDoc._doc.pendingCallbacks.should.deep.equal []
  108. describe "flushPendingOps", ->
  109. beforeEach ->
  110. @shareJsDoc = new ShareJsDoc(@doc_id, @lines, @version, @socket)
  111. @shareJsDoc._doc.flush = sinon.stub()
  112. @shareJsDoc.flushPendingOps()
  113. it "should call _doc.flush", ->
  114. @shareJsDoc._doc.flush.called.should.equal true
  115. describe "updateConnectionState", ->
  116. beforeEach ->
  117. @shareJsDoc = new ShareJsDoc(@doc_id, @lines, @version, @socket)
  118. @shareJsDoc._doc._connectionStateChanged = sinon.stub()
  119. @shareJsDoc._doc.autoOpen = true
  120. @socket.socket.sessionid = "new-connection-id"
  121. @shareJsDoc.updateConnectionState "mock-state"
  122. it "should set autoOpen to false so that ShareJs doesn't try to send an open message", ->
  123. @shareJsDoc._doc.autoOpen.should.equal false
  124. it "should update the connection state", ->
  125. @shareJsDoc.connection.state.should.equal "mock-state"
  126. it "should notify the ShareJs doc of the state change", ->
  127. @shareJsDoc._doc._connectionStateChanged
  128. .calledWith("mock-state")
  129. .should.equal true
  130. it "should set the connection id to the latest socket id", ->
  131. @shareJsDoc.connection.id.should.equal "new-connection-id"
  132. describe "hasBufferedOps", ->
  133. describe "with inflight ops", ->
  134. beforeEach ->
  135. @shareJsDoc = new ShareJsDoc(@doc_id, @lines, @version, @socket)
  136. @shareJsDoc._doc.inflightOp = "mock-op-1"
  137. it "should return true", ->
  138. @shareJsDoc.hasBufferedOps().should.equal true
  139. describe "with pending ops", ->
  140. beforeEach ->
  141. @shareJsDoc = new ShareJsDoc(@doc_id, @lines, @version, @socket)
  142. @shareJsDoc._doc.pendingOp = "mock-op-1"
  143. it "should return true", ->
  144. @shareJsDoc.hasBufferedOps().should.equal true
  145. describe "with no buffered ops", ->
  146. beforeEach ->
  147. @shareJsDoc = new ShareJsDoc(@doc_id, @lines, @version, @socket)
  148. it "should return false", ->
  149. @shareJsDoc.hasBufferedOps().should.equal false
  150. describe "processUpdateFromServer", ->
  151. describe "successfully", ->
  152. beforeEach ->
  153. @shareJsDoc = new ShareJsDoc(@doc_id, @lines, @version, @socket)
  154. @shareJsDoc._doc._onMessage = sinon.stub()
  155. @shareJsDoc.processUpdateFromServer "mock-message"
  156. it "should pass the message onto the ShareJs Doc", ->
  157. @shareJsDoc._doc._onMessage
  158. .calledWith( "mock-message" )
  159. .should.equal true
  160. describe "with an error", ->
  161. beforeEach ->
  162. @shareJsDoc = new ShareJsDoc(@doc_id, @lines, @version, @socket)
  163. sinon.spy @shareJsDoc, "trigger"
  164. @shareJsDoc._doc._onMessage = sinon.stub().throws(@error = {message: "Mock error"})
  165. @shareJsDoc.processUpdateFromServer "mock-message"
  166. it "should trigger the error handler", ->
  167. @shareJsDoc.trigger
  168. .calledWith("error", @error)
  169. .should.equal true
  170. describe "with an external update", ->
  171. beforeEach ->
  172. @shareJsDoc = new ShareJsDoc(@doc_id, @lines, @version, @socket)
  173. @shareJsDoc._doc._onMessage = sinon.stub()
  174. sinon.spy @shareJsDoc, "trigger"
  175. @shareJsDoc.processUpdateFromServer { op: "mock-op", meta: { type: "external" } }
  176. it "should trigger an externalUpdate event", ->
  177. @shareJsDoc.trigger
  178. .calledWith("externalUpdate")
  179. .should.equal true
  180. describe "catchUp", ->
  181. beforeEach ->
  182. @shareJsDoc = new ShareJsDoc(@doc_id, @lines, @version, @socket)
  183. sinon.stub @shareJsDoc, "processUpdateFromServer", () ->
  184. @_doc.version++
  185. @shareJsDoc.catchUp [{
  186. ops: ["mock-op-1"]
  187. }, {
  188. ops: ["mock-op-2"]
  189. }]
  190. it "should apply each update", ->
  191. @shareJsDoc.processUpdateFromServer
  192. .calledWith({
  193. doc: @doc_id
  194. v: @version
  195. ops: ["mock-op-1"]
  196. })
  197. .should.equal true
  198. @shareJsDoc.processUpdateFromServer
  199. .calledWith({
  200. doc: @doc_id
  201. v: @version + 1
  202. ops: ["mock-op-2"]
  203. })
  204. .should.equal true