UNPKG

ripple-core

Version:

Ripple is an interactive audience response system that allows presenters to survey audience members in real time communication through their mobile devices.

605 lines (513 loc) 18.3 kB
// Allow coverage reporting var libpath = process.env['PLUGIN_COV'] ? '../lib-cov' : '../lib'; var should = require("should") , sinon = require("sinon") , SM = require(libpath + "/set-manager.js") , DB = require(libpath + "/db-manager.js") describe("Set Manager", function() { var collections; var oldCollections; beforeEach(function() { // Set up empty collection objects - tests must set up functions / stubs if needed collections = { sets: {}, questions: {} } // Don't lose old collections and potentially blow up other tests oldCollections = { sets: SM.sets, questions: SM.questions } SM.sets = collections.sets; SM.questions = collections.questions; }); afterEach(function() { SM.sets = oldCollections.sets; SM.questions = oldCollections.questions; }); describe("#createSet", function() { var req, res, o, insertRec, records; beforeEach(function() { req = { body: { name: "set name", class: "Foo 101" }, session: {} }; res = { redirect: function() {}, send: function() {} }; o = {_id: "user id"}; records = [ { _id: "set-id", name: "set name" } ]; insertRec = sinon.stub(DB, "insertRec"); }); afterEach(function() { insertRec.restore(); }); it("should call insertRec with form data", function() { SM.createSet(req, res, o); insertRec.withArgs(SM.sets, {name: "set name", class: "Foo 101", authorID: "user id"}, sinon.match.func).callCount.should.eql(1); }); describe("(when insertRec succeeds)", function() { beforeEach(function() { insertRec.yields(null, records); }); it("should set the questionSet session data", function() { SM.createSet(req, res, o); req.session.questionSet.should.eql({id: "set-id"}); }); it("should redirect to the set's edit page", function() { var redirect = sinon.stub(res, "redirect"); SM.createSet(req, res, o); redirect.callCount.should.eql(1); redirect.withArgs("admin/set/edit/set-id~set name").callCount.should.eql(1); }); }); describe("(when insertRec has errors)", function() { var err; beforeEach(function() { err = {name: "Error"}; insertRec.yields(err); }); it("should send an error", function() { var send = sinon.stub(res, "send"); SM.createSet(req, res, o); send.callCount.should.eql(1); send.withArgs(err, 400).callCount.should.eql(1); }); }); }); describe("#getSetQuestions", function() { var getSet, getQfromSet, sortQuestions, setRecord, setQuestions; beforeEach(function() { getSet = sinon.stub(SM, "getSet"); getQfromSet= sinon.stub(SM, "getQfromSet"); sortQuestions= sinon.stub(SM, "sortQuestions"); setRecord = { _id: "set-id", question: [1,2,3] }; setQuestions = [{_id: 1}, {_id: 2}, {_id: 3}]; }); afterEach(function() { getSet.restore(); getQfromSet.restore(); sortQuestions.restore(); }); it("should call getSet with the given setID", function(done) { // Hack in an error just to get through the function quickly - only looking to verify // function call here getSet.yields("err"); SM.getSetQuestions("set-id", null, function(err, questions) { getSet.withArgs("set-id", sinon.match.func).callCount.should.eql(1); done(); }); }); describe("(when getSet has an error)", function() { it("should call callback with an error object and no data", function(done) { getSet.yields("fake error message"); SM.getSetQuestions("set-id", null, function(err, questions) { should.exist(err); err.name.should.eql("DatabaseError"); done(); }); }); }); describe("(when no record is found)", function() { it("should call callback with an error object and no data", function(done) { getSet.yields(null, null); SM.getSetQuestions("set-id", null, function(err, questions) { should.exist(err); err.name.should.eql("NoRecord"); done(); }); }); }); describe("(when a record is found)", function() { beforeEach(function() { getSet.yields(null, setRecord); }); describe("(when the record has no questions)", function() { beforeEach(function() { setRecord.question = null; }); it("should call callback with an empty array of questions", function(done) { SM.getSetQuestions("set-id", null, function(err, questions) { should.not.exist(err); questions.should.eql([]); done(); }); }); }); describe("(when the record has questions)", function() { it("should call SM.getQfromSet with the record's questions", function(done) { // As above, hack in an error to simplify testing the call getQfromSet.yields("error"); SM.getSetQuestions("set-id", null, function(err, questions) { getQfromSet.withArgs(setRecord.question, sinon.match.func).callCount.should.eql(1); done(); }); }); describe("(when SM.getQfromSet has an error)", function() { beforeEach(function() { getQfromSet.yields("error"); }); it("should call callback with an error", function(done) { SM.getSetQuestions("set-id", null, function(err, questions) { should.exist(err); err.name.should.eql("MissingQuestions"); done(); }); }); }); describe("(when SM.getQfromSet finds no data)", function() { beforeEach(function() { getQfromSet.yields(); }); it("should call callback with an error", function(done) { SM.getSetQuestions("set-id", null, function(err, questions) { should.exist(err); err.name.should.eql("MissingQuestions"); done(); }); }); }); describe("(when SM.getQfromSet finds questions)", function() { beforeEach(function() { getQfromSet.yields(null, setQuestions); sortQuestions.yields(); }); it("should dispatch callback to sortQuestions", function(done) { SM.getSetQuestions("set-id", null, function(err, questions) { sortQuestions.withArgs(setRecord.question, setQuestions, null, sinon.match.func).callCount.should.eql(1); done(); }); }); }); }); }); }); describe("#getSet", function() { var findOne; beforeEach(function() { SM.sets.findOne = function() {}; findOne = sinon.stub(SM.sets, "findOne"); }); afterEach(function() { findOne.restore(); }); it("should call findOne with the given record ID converted to an object id", function(done) { findOne.yields(); SM.getSet("some id xyzz", function(err, record) { findOne.callCount.should.eql(1); var args = findOne.getCall(0).args; args[0].should.eql({ _id: DB.getObjID("some id xyzz") }) done(); }); }); it("should dispatch errors to callback", function(done) { findOne.yields("error"); SM.getSet("some id xyzz", function(err, record) { err.should.eql("error"); should.not.exist(record); done(); }); }); it("should dispatch success to callback", function(done) { findOne.yields(null, "record"); SM.getSet("some id xyzz", function(err, record) { should.not.exist(err); record.should.eql("record"); done(); }); }); }); describe("#getQfromSet", function() { var find, qNumArray, cursor, toArray; beforeEach(function() { SM.questions.find = function() {}; find = sinon.stub(SM.questions, "find"); qNumArray = [1, 2, 3]; cursor = {toArray: function() {}}; toArray = sinon.stub(cursor, "toArray"); }); afterEach(function() { find.restore(); toArray.restore(); }); it("should look for all questions with an id in the array passed in", function(done) { find.yields(); SM.getQfromSet(qNumArray, function(err, records) { find.callCount.should.eql(1); var args = find.getCall(0).args; args[0].should.eql({_id: {$in: qNumArray}}); done(); }); }); describe("(when there is no cursor)", function() { it("should call callback with error", function(done) { find.yields("error"); SM.getQfromSet(qNumArray, function(err, records) { err.should.eql("error"); should.not.exist(records); done(); }); }); it("should call callback with null if no error occurred", function(done) { find.yields(); SM.getQfromSet(qNumArray, function(err, records) { should.not.exist(err); should.not.exist(records); done(); }); }); }); describe("(when there is a cursor)", function() { beforeEach(function() { find.yields(null, cursor); }); it("should call cursor.toArray", function(done) { toArray.yields(); SM.getQfromSet(qNumArray, function(err, records) { toArray.callCount.should.eql(1); done(); }); }); it("should call callback with cursor.toArray results", function(done) { toArray.yields(1, "two"); SM.getQfromSet(qNumArray, function(err, records) { err.should.eql(1); records.should.eql("two"); done(); }); }); }); }); describe("#sortQuestions", function() { var objects, ids; beforeEach(function() { objects = [ {_id: 1, name: "one"}, {_id: 2, name: "two"}, {_id: 3, name: "three"}, {_id: 4, name: "four"}, {_id: 5, name: "five"}, {_id: 6, name: "six"}, {_id: 7, name: "seven"} ]; ids = [1, 5, 2, 7, 4]; }); describe("(when successful)", function() { it("should call callback with the sorted array of objects", function(done) { SM.sortQuestions(ids, objects, null, function(err, sorted) { should.not.exist(err); // This is verbose, but more easy to debug sort issues sorted[0]._id.should.eql(1); sorted[0].name.should.eql("one"); sorted[1]._id.should.eql(5); sorted[1].name.should.eql("five"); sorted[2]._id.should.eql(2); sorted[2].name.should.eql("two"); sorted[3]._id.should.eql(7); sorted[3].name.should.eql("seven"); sorted[4]._id.should.eql(4); sorted[4].name.should.eql("four"); sorted.length.should.eql(ids.length); done(); }); }); }); }); describe("#createQuestion", function() { var insertRec, user, setUpdate, req, res, user, setID, insertRecords; beforeEach(function() { insertRec = sinon.stub(DB, "insertRec"); SM.sets.update = function() {}; setUpdate = sinon.stub(SM.sets, "update"); // Parameters for the call to createQuestion req = {body: {qType: "qtype"}}; res = {}; user = {_id: "user-id"}; setID = "setid12chars"; // Records returned by insertRec insertRecords = [{_id: 1, name: "first"}, {_id: 2, name: "second"}]; }); afterEach(function() { insertRec.restore(); setUpdate.restore(); }); it("should call insertRec to create a new question", function(done) { insertRec.yields(null, insertRecords); setUpdate.yields(); SM.createQuestion(req, res, user, setID, function(err, record) { insertRec.callCount.should.eql(1); var args = insertRec.getCall(0).args; args[0].should.eql(SM.questions); args[1].should.eql({type: "qtype", authorID: "user-id", setID: DB.getObjID(setID)}); done(); }); }); it("should call update on the sets collection to add the new question to the end of the questions list", function(done) { insertRec.yields(null, insertRecords); setUpdate.yields(); SM.createQuestion(req, res, user, setID, function(err, record) { setUpdate.callCount.should.eql(1); var args = setUpdate.getCall(0).args; args[0].should.eql({_id: DB.getObjID(setID)}); args[1].should.eql({ $push: {question: insertRecords[0]._id} }); done(); }); }); it("should call callback with insertRec's err and first record", function(done) { insertRec.yields("error", insertRecords); setUpdate.yields(); SM.createQuestion(req, res, user, setID, function(err, record) { err.should.eql("error"); record.should.eql(insertRecords[0]); done(); }); }); }); describe("#updateQuestion", function() { var update, qid, updateData; beforeEach(function() { SM.questions.update = function() {}; update = sinon.stub(SM.questions, "update"); // Parameters for the call to updateQuestion qid = "qid 12 chars"; updateData = {"qOptions.foo": "placeholder"}; }); afterEach(function() { update.restore(); }); describe("(when qTxt is present)", function() { beforeEach(function () { updateData.qTxt = "I am here!" }); it("should call update on the questions with the passed-in update options", function(done) { update.yields(); SM.updateQuestion(qid, updateData, function(err) { update.callCount.should.eql(1); var args = update.getCall(0).args; args[0].should.eql({_id: DB.getObjID(qid)}); args[1].should.eql({ $set: {"qOptions.foo": "placeholder", qTxt: "I am here!"} }); done(); }); }); it("should call callback with update's error", function(done) { update.yields("my error!"); SM.updateQuestion(qid, updateData, function(err) { err.should.eql("my error!"); done(); }); }); }); describe("(when qTxt is not present)", function() { it("should call update on the questions without modifications to data", function(done) { update.yields(); SM.updateQuestion(qid, updateData, function(err) { update.callCount.should.eql(1); var args = update.getCall(0).args; args[0].should.eql({_id: DB.getObjID(qid)}); args[1].should.eql({ $set: {"qOptions.foo": "placeholder"} }); done(); }); }); it("should call callback with update's error", function(done) { update.yields("my error!"); SM.updateQuestion(qid, updateData, function(err) { err.should.eql("my error!"); done(); }); }); }); }); describe("#removeQuestion", function() { var remove, qid, setid, setUpdate; beforeEach(function() { SM.questions.remove = function() {}; remove = sinon.stub(SM.questions, "remove"); SM.sets.update = function() {}; setUpdate = sinon.stub(SM.sets, "update"); // Parameters for the call to removeQuestion qid = "qid 12 chars"; setid = "setid12chars"; }); afterEach(function() { remove.restore(); setUpdate.restore(); }); it("should call remove with the qid", function(done) { remove.yields(); setUpdate.yields(); SM.removeQuestion(qid, setid, function(err) { remove.callCount.should.eql(1); var args = remove.getCall(0).args; args[0].should.eql({_id: DB.getObjID(qid)}); done(); }); }); describe("(when remove call has an error)", function() { beforeEach(function () { remove.yields("removeErr"); }); it("should call callback with remove's error", function(done) { SM.removeQuestion(qid, setid, function(err) { err.should.eql("removeErr"); done(); }); }); it("shouldn't call set update", function(done) { SM.removeQuestion(qid, setid, function(err) { setUpdate.callCount.should.eql(0); done(); }); }); }); describe("(when remove call is successful)", function() { beforeEach(function () { remove.yields(null); }); it("should call set update on setid to pull question qid", function(done) { setUpdate.yields(); SM.removeQuestion(qid, setid, function(err) { setUpdate.callCount.should.eql(1); var args = setUpdate.getCall(0).args; args[0].should.eql({_id: DB.getObjID(setid)}); args[1].should.eql({ $pull: {question: DB.getObjID(qid)} }); done(); }); }); it("should call callback with update's error", function(done) { setUpdate.yields("setUpdate err"); SM.removeQuestion(qid, setid, function(err) { err.should.eql("setUpdate err"); done(); }); }); }); }); describe("#updateOrder", function() { var setUpdate, setid, ids; beforeEach(function() { SM.sets.update = function() {}; setUpdate = sinon.stub(SM.sets, "update"); // Parameters for the call to updateOrder setid = "setid12chars"; ids = ["abcdefghijkl", "mnopqrstuvwx", "123456789012"]; }); afterEach(function() { setUpdate.restore(); }); it("should call update with the new qid array", function(done) { setUpdate.yields(); SM.updateOrder(setid, ids, function(err) { setUpdate.callCount.should.eql(1); var args = setUpdate.getCall(0).args; args[0].should.eql({_id: DB.getObjID(setid)}); args[1].should.eql({ $set: {question: [DB.getObjID(ids[0]), DB.getObjID(ids[1]), DB.getObjID(ids[2])]} }); done(); }); }); it("should call callback with update's err", function(done) { setUpdate.yields('error'); SM.updateOrder(setid, ids, function(err) { err.should.eql("error"); done(); }); }); }); });