Files
panic-server/test/index.js
Jesse Gibson b220402001 Add method .atLeast
Resolves when a minimum number of clients join (or have joined) your
list.
2016-10-03 17:51:27 -06:00

277 lines
7.0 KiB
JavaScript

/*globals beforeEach, describe, it*/
'use strict';
var mock = require('./mock');
var Client = mock.Client;
var ClientList = require('../src/ClientList');
var Promise = require('bluebird');
var expect = require('chai').expect;
describe('A clientList', function () {
var list, client;
beforeEach(function () {
list = new ClientList();
client = new Client({
name: 'Node.js'
});
});
it('should emit when a client is added', function () {
var fired = false;
list.on('add', function () {
fired = true;
}).add(client);
expect(fired).to.eq(true);
});
it('should emit when a client is removed', function () {
var fired = false;
list.on('remove', function () {
fired = true;
})
.add(client)
.remove(client);
expect(fired).to.eq(true);
});
it('should return length when "len()" is called', function () {
list.add(client);
expect(list.length).to.eq(1);
list.remove(client);
expect(list.length).to.eq(0);
});
it('should not add disconnected clients', function () {
client.socket.connected = false;
list.add(client);
expect(list.length).to.eq(0);
});
it('should remove a client on disconnect', function () {
list.add(client);
expect(list.length).to.eq(1);
client.socket.emit('disconnect');
expect(list.length).to.eq(0);
});
it('should resolve a promise when all clients finish', function (done) {
client.socket.on('run', function (cb, jobID) {
client.socket.emit(jobID);
});
list.add(client).run(function () {})
.then(function () {
done();
})
.catch(done);
});
it('should reject a promise if an error is sent', function (done) {
client.socket.on('run', function (cb, job) {
client.socket.emit(job, 'fake error');
});
list.add(client).run(function () {})
.catch(function (err) {
expect(err).to.eq('fake error');
done();
});
});
it('should not emit "add" if it contains the client', function () {
var called = 0;
list.on('add', function () {
called += 1;
});
list.add(client);
list.add(client);
expect(called).to.eq(1);
});
describe('filter', function () {
it('should not mutate the original list', function () {
list.add(client);
expect(list.length).to.eq(1);
list.filter(function () {
return false;
});
expect(list.length).to.eq(1);
});
it('should return a new, filtered list', function () {
list.add(client);
var servers = list.filter('Node.js');
var browsers = list.filter(function (client) {
return client.platform.name !== 'Node.js';
});
expect(servers.length).to.eq(1);
expect(browsers.length).to.eq(0);
});
it('should be reactive to changes to the parent list', function () {
var servers = list.filter('Node.js');
expect(servers.length).to.eq(0);
list.add(client);
expect(servers.length).to.eq(1);
});
});
describe('exclusion', function () {
it('should not contain excluded clients', function () {
list.add(client);
var filtered = list.excluding(list);
expect(filtered.length).to.eq(0);
});
it('should react to removals if they are connected', function () {
var decoy = new Client();
var exclusion = new ClientList()
.add(client)
.add(decoy);
var filtered = list.excluding(exclusion);
list.add(client).add(new Client());
expect(filtered.length).to.eq(1);
exclusion.remove(client).remove(decoy);
expect(filtered.length).to.eq(2);
});
});
describe('number constraint', function () {
it('should return no more than the number requested', function () {
list.add(client)
.add(new Client())
.add(new Client());
expect(list.pluck(1).length).to.eq(1);
});
it('should listen for additions', function () {
var subset = list.pluck(2);
expect(subset.length).not.to.eq(2);
list.add(new Client()).add(new Client());
expect(subset.length).to.eq(2);
list.add(new Client());
expect(subset.length).to.eq(2);
});
it('should replace a client when it disconnects', function () {
var subset = list.pluck(1);
list.add(client).add(new Client());
expect(subset.length).to.eq(1);
client.socket.emit('disconnect');
// It should be replaced with
// the second connected client.
expect(subset.length).to.eq(1);
});
it('should set a flag whether the constraint is met', function () {
var subset = list.pluck(1);
expect(subset.atCapacity).to.eq(false);
list.add(client);
expect(subset.atCapacity).to.eq(true);
client.socket.emit('disconnect');
expect(subset.atCapacity).to.eq(false);
});
it('should play well with exclusions', function () {
var bob, alice = list.pluck(1);
bob = list.excluding(alice).pluck(1);
list.add(client)
.add(new Client())
.add(new Client());
expect(alice.length).to.eq(1);
expect(bob.length).to.eq(1);
});
});
describe('minimum qualifier', function () {
it('should resolve when the minimum is reached', function () {
var promise = list.atLeast(1);
var called = false;
promise.then(function () {
called = true;
});
expect(called).to.eq(false);
list.add(new Client());
// Mocha will wait for this to resolve.
return promise;
});
it('should resolve if the min is already reached', function () {
var promise = list.atLeast(0);
// This will time out if unresolved.
return promise;
});
it('should resolve to undefined', function () {
function validate (arg) {
expect(arg).to.eq(undefined);
}
var immediate = list.atLeast(0).then(validate);
var later = list.atLeast(1).then(validate);
list.add(new Client());
return Promise.all([immediate, later]);
});
it('should resolve if it has more than enough', function () {
list.add(new Client()).add(new Client());
return list.atLeast(1);
});
it('should unsubscribe after resolving', function () {
list.atLeast(1);
expect(list.listenerCount('add')).to.eq(1);
list.add(new Client());
expect(list.listenerCount('add')).to.eq(0);
});
});
});
describe('The ClientList constructor', function () {
var list1, list2, client1, client2;
beforeEach(function () {
list1 = new ClientList();
list2 = new ClientList();
client1 = new Client();
client2 = new Client();
list1.add(client1);
list2.add(client2);
});
it('should accept an array of clientLists', function () {
var list = new ClientList([list1, list2]);
// it should contain both clients
expect(list.get(client1.socket.id)).to.eq(client1);
expect(list.get(client2.socket.id)).to.eq(client2);
});
it('should reactively add new clients from source lists', function () {
var list = new ClientList([list1, list2]);
var client3 = new Client();
expect(list.get(client3.socket.id)).to.eq(null);
list1.add(client3);
expect(list.get(client3.socket.id)).to.eq(client3);
});
it('should be subclassable', function () {
function Sub() {
ClientList.call(this);
}
Sub.prototype = new ClientList();
Sub.prototype.constructor = Sub;
var sub = new Sub();
expect(sub).to.be.an.instanceof(Sub);
// chained inheritance
expect(sub.filter('Firefox')).to.be.an.instanceof(Sub);
expect(sub.pluck(1)).to.be.an.instanceof(Sub);
});
});