diff --git a/lib/client/connection.js b/lib/client/connection.js index 19a332bdf..f8adb9513 100644 --- a/lib/client/connection.js +++ b/lib/client/connection.js @@ -5,6 +5,11 @@ var ShareDBError = require('../error'); var types = require('../types'); var util = require('../util'); +function connectionState(socket) { + if (socket.readyState === 0 || socket.readyState === 1) return 'connecting'; + return 'disconnected'; +} + /** * Handles communication with the sharejs server and provides queries and * documents. @@ -48,6 +53,8 @@ function Connection(socket) { this.debug = false; + this.state = connectionState(socket); + this.bindToSocket(socket); } emitter.mixin(Connection); @@ -90,7 +97,8 @@ Connection.prototype.bindToSocket = function(socket) { // - 'disconnected' Connection is closed, but it will reconnect automatically // - 'closed' The connection was closed by the client, and will not reconnect // - 'stopped' The connection was closed by the server, and will not reconnect - this.state = (socket.readyState === 0 || socket.readyState === 1) ? 'connecting' : 'disconnected'; + var newState = connectionState(socket); + this._setState(newState); // This is a helper variable the document uses to see whether we're // currently in a 'live' state. It is true if and only if we're connected diff --git a/test/client/connection.js b/test/client/connection.js index d579573fd..a3681c0cb 100644 --- a/test/client/connection.js +++ b/test/client/connection.js @@ -1,5 +1,6 @@ var expect = require('expect.js'); var Backend = require('../../lib/backend'); +var Connection = require('../../lib/client/connection'); describe('client connection', function() { @@ -90,4 +91,71 @@ describe('client connection', function() { }); }); + describe('state management using setSocket', function() { + it('initial connection.state is connecting, if socket.readyState is CONNECTING', function () { + // https://html.spec.whatwg.org/multipage/web-sockets.html#dom-websocket-connecting + var socket = { readyState: 0 } + var connection = new Connection(socket) + expect(connection.state).equal('connecting'); + }); + + it('initial connection.state is connecting, if socket.readyState is OPEN', function () { + // https://html.spec.whatwg.org/multipage/web-sockets.html#dom-websocket-open + var socket = { readyState: 1 } + var connection = new Connection(socket) + expect(connection.state).equal('connecting'); + }); + + it('initial connection.state is disconnected, if socket.readyState is CLOSING', function () { + // https://html.spec.whatwg.org/multipage/web-sockets.html#dom-websocket-closing + var socket = { readyState: 2 } + var connection = new Connection(socket) + expect(connection.state).equal('disconnected'); + }); + + it('initial connection.state is disconnected, if socket.readyState is CLOSED', function () { + // https://html.spec.whatwg.org/multipage/web-sockets.html#dom-websocket-closed + var socket = { readyState: 3 } + var connection = new Connection(socket) + expect(connection.state).equal('disconnected'); + }); + + it('initial state is connecting', function() { + var connection = this.backend.connect(); + expect(connection.state).equal('connecting'); + }); + + it('after connected event is emitted, state is connected', function(done) { + var connection = this.backend.connect(); + connection.on('connected', function() { + expect(connection.state).equal('connected'); + done(); + }); + }); + + it('when connection is manually closed, state is closed', function(done) { + var connection = this.backend.connect(); + connection.on('connected', function() { + connection.close(); + }); + connection.on('closed', function() { + expect(connection.state).equal('closed'); + done(); + }); + }); + + it('when connection is disconnected, state is disconnected', function(done) { + var connection = this.backend.connect(); + connection.on('connected', function() { + // Mock a disconnection by providing a reason + connection.socket.close('foo'); + }); + connection.on('disconnected', function() { + expect(connection.state).equal('disconnected'); + done(); + }); + }); + + }); + });