Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add port option to socket client, tests for Styleguide service, defer socket event listener registrations until connection #430

Merged
merged 4 commits into from
Jan 21, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 40 additions & 21 deletions lib/app/js/services/Socket.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,22 @@ angular.module('sgApp')

var socket,
connected = false,
port = '',
deferredEventListeners = [],
service = {

setPort: function(serverPort) {
port = serverPort;
},
isAvailable: function() {
return (typeof window.io !== 'undefined');
return (typeof $window.io !== 'undefined');
},
on: function(eventName, listener) {
if (socket) {
deferredEventListeners.push({
event: eventName,
listener: listener
});

if (this.isConnected()) {
socket.on(eventName, function() {
var args = arguments;
$rootScope.$apply(function() {
Expand All @@ -20,7 +29,6 @@ angular.module('sgApp')
});
}
},

emit: function(eventName, data, callback) {
if (socket) {
socket.emit(eventName, data, function() {
Expand All @@ -33,30 +41,41 @@ angular.module('sgApp')
});
}
},

isConnected: function() {
return connected;
}
return socket !== undefined && connected === true;
},
connect: connect
};

if (service.isAvailable()) {
socket = $window.io.connect('/');

service.on('connect', function() {
connected = true;
$rootScope.$broadcast('socket connected');
});
function connect() {
if (service.isAvailable()) {
var url = port ? ':' + port + '/' : '/';
if (connected) {
socket.disconnect();
}

service.on('disconnect', function() {
connected = false;
$rootScope.$broadcast('socket disconnected');
});
socket = $window.io.connect(url);

service.on('error', function(err) {
$rootScope.$broadcast('socket error', err);
});
deferredEventListeners.forEach(function(deferred) {
socket.on(deferred.event, deferred.listener);
});
}
}

service.on('connect', function() {
connected = true;
$rootScope.$broadcast('socket connected');
});

service.on('disconnect', function() {
connected = false;
$rootScope.$broadcast('socket disconnected');
});

service.on('error', function(err) {
$rootScope.$broadcast('socket error', err);
});

return service;

});
5 changes: 5 additions & 0 deletions lib/app/js/services/Styleguide.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ angular.module('sgApp')
_this.config.data = response.config;
_this.variables.data = response.variables;
_this.sections.data = response.sections;

if (!Socket.isConnected()) {
Socket.setPort(response.config.port);
Socket.connect();
}
});
};

Expand Down
6 changes: 3 additions & 3 deletions lib/styleguide.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ function sanitizeOptions(opt) {
commonClass: opt.commonClass || '',
styleVariables: opt.styleVariables || false,
server: opt.server || false,
port: opt.port,
port: opt.port || 3000,
rootPath: opt.rootPath,
filesConfig: opt.filesConfig
};
Expand Down Expand Up @@ -88,7 +88,7 @@ function generateInheritedWrappers(json) {
}

function copyUsedOptionsToJsonConfig(opt, json) {
var used = ['appRoot', 'extraHead', 'commonClass', 'title'];
var used = ['appRoot', 'extraHead', 'commonClass', 'title', 'port'];
json.config = {};
used.forEach(function(prop) {
json.config[prop] = _.cloneDeep(opt[prop]);
Expand Down Expand Up @@ -362,7 +362,7 @@ module.exports.server = function(options) {
};

function startServer(options) {
var port = options.port || 3000;
var port = options.port;
// Ignore start server if we alrady have instance running
if (!serverInstance) {
serverInstance = sgServer(options);
Expand Down
121 changes: 96 additions & 25 deletions test/angular/unit/services/Socket.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,15 @@ describe('Service: Socket', function() {
var service,
rootScope,
fakeIo,
fakeSocket;
fakeSocket,
fakeWindow = {};

beforeEach(angular.mock.module('sgApp'));

beforeEach(module(function($provide) {
$provide.value('$window', fakeWindow);
}));

beforeEach(function() {
fakeSocket = {
listeners: {},
Expand All @@ -25,10 +30,11 @@ describe('Service: Socket', function() {
if (cb) {
cb.call(undefined);
}
})
}),
disconnect: sinon.spy()
};

window.io = fakeIo = {
fakeWindow.io = fakeIo = {
connect: sinon.stub().returns(fakeSocket)
};

Expand All @@ -38,15 +44,40 @@ describe('Service: Socket', function() {
});
});

it('connects to path "/" using window.io', function() {
expect(fakeIo.connect).to.have.been.calledWith('/');
describe('.connect()', function() {

it('does not try to connect if socket.io is not available', function() {
delete fakeWindow.io;
service.connect();
expect(fakeIo.connect).not.to.have.been.called;
});

it('connects to path "/" using window.io when no port is set', function() {
service.connect();
expect(fakeIo.connect).to.have.been.calledWith('/');
});

it('connects to path ":<port>/" using window.io when port is set', function() {
service.setPort(3298);
service.connect();
expect(fakeIo.connect).to.have.been.calledWith(':3298/');
});

it('calls socket.disconnect() if already connected', function() {
connect();
expect(service.isConnected()).to.eql(true);
service.connect();
expect(fakeSocket.disconnect).to.have.been.called;
});

});

describe('socket event listener', function() {

var broadcast;
beforeEach(function() {
broadcast = sinon.spy(rootScope, '$broadcast');
connect();
});

it('for "connect" is broadcast via $rootScope as "socket connected" event', function() {
Expand Down Expand Up @@ -74,17 +105,39 @@ describe('Service: Socket', function() {
beforeEach(function() {
listener = sinon.spy();
apply = sinon.spy(rootScope, '$apply');
service.on('onTest', listener);
});

it('registers socket event listener with the same name', function() {
expect(fakeSocket.listeners.onTest.length).to.eql(1);
describe('when socket connection is open', function() {

beforeEach(function() {
connect();
service.on('onTest', listener);
});

it('registers socket event listener with the same name', function() {
expect(fakeSocket.listeners.onTest.length).to.eql(1);
});

it('applies the listener function through $rootScope.$apply', function() {
fakeSocket.emit('onTest');
expect(apply).to.have.been.called;
expect(listener).to.have.been.called;
});

});

it('applies the listener function through $rootScope.$apply', function() {
fakeSocket.emit('onTest');
expect(apply).to.have.been.called;
expect(listener).to.have.been.called;
describe('when socket connection is not open', function() {

beforeEach(function() {
service.on('onTest', listener);
});

it('registers socket event listener with the same name when socket connects', function() {
expect(fakeSocket.listeners.onTest).to.be.undefined;
connect();
expect(fakeSocket.listeners.onTest.length).to.eql(1);
});

});

});
Expand All @@ -98,20 +151,32 @@ describe('Service: Socket', function() {
apply = sinon.spy(rootScope, '$apply');
});

it('emits a socket event with the same name', function() {
it('does nothing when socket is not available', function() {
service.emit('emitTest');
expect(fakeSocket.emit).to.have.been.calledWith('emitTest');
expect(fakeSocket.emit).not.to.have.been.called;
expect(apply).not.to.have.been.called;
});

it('passes the given data object to socket.emit', function() {
service.emit('emitTest', data);
expect(fakeSocket.emit).to.have.been.calledWith('emitTest', data);
});
describe('when socket is available', function() {

beforeEach(connect);

it('emits a socket event with the same name', function() {
service.emit('emitTest');
expect(fakeSocket.emit).to.have.been.calledWith('emitTest');
});

it('passes the given data object to socket.emit', function() {
service.emit('emitTest', data);
expect(fakeSocket.emit).to.have.been.calledWith('emitTest', data);
});

it('applies the callback through $rootScope.$apply', function() {
service.emit('emitTest', data, callback);
expect(apply).to.have.been.called;
expect(callback).to.have.been.called;
});

it('applies the callback through $rootScope.$apply', function() {
service.emit('emitTest', data, callback);
expect(apply).to.have.been.called;
expect(callback).to.have.been.called;
});

});
Expand All @@ -123,12 +188,13 @@ describe('Service: Socket', function() {
});

it('returns true after socket has emitted "connect" event', function() {
service.connect();
fakeSocket.emit('connect');
expect(service.isConnected()).to.eql(true);
});

it('returns false after socket has emitted "disconnect" event', function() {
fakeSocket.emit('connect');
connect();
expect(service.isConnected()).to.eql(true);
fakeSocket.emit('disconnect');
expect(service.isConnected()).to.eql(false);
Expand All @@ -139,15 +205,20 @@ describe('Service: Socket', function() {
describe('.isAvailable()', function() {

it('returns true if window.io is not undefined', function() {
window.io = sinon.stub();
fakeWindow.io = sinon.stub();
expect(service.isAvailable()).to.eql(true);
});

it('returns false if window.io is undefined', function() {
window.io = undefined;
delete fakeWindow.io;
expect(service.isAvailable()).to.eql(false);
});

});

function connect() {
service.connect();
fakeSocket.emit('connect');
}

});
Loading