<commit_before>var expect = require('expect.js');
var Blob = require('blob');
var ss = require('../');
var support = require('./support');
var client = support.client;

describe('socket.io-stream', function() {
  this.timeout(70000);

  it('should send/receive a file', function(done) {
    var sums = [];
    var socket = client();
    socket.on('connect', function() {
      var file = ss.createStream();
      ss(socket).emit('read', file, 'test/support/frog.jpg', function(sum) {
        check(sum);
      });

      var checksum = ss.createStream();
      ss(socket).emit('checksum', checksum, function(sum) {
        check(sum);
      });

      file.pipe(checksum);

      function check(sum) {
        sums.push(sum);
        if (sums.length < 2) return;
        expect(sums[0]).to.equal(sums[1]);
        socket.disconnect();
        done();
      }
    });
  });

  it('should send/receive data in flowing mode', function(done) {
    var socket = client();
    socket.on('connect', function() {
      var stream = ss.createStream();
      ss(socket)
        .emit('echo', stream, { hi: 1 })
        .on('echo', function(stream, obj) {
          expect(obj).to.eql({ hi: 1 });

          var data = '';
          stream.on('data', function(chunk) {
            data += chunk;
          }).on('end', function() {
            expect(data).to.equal('foobar');
            socket.disconnect();
            done();
          });
        });

      stream.write('foo');
      stream.write('bar');
      stream.end();
    });
  });

  it('should send/receive data in paused mode', function(done) {
    var socket = client();
    socket.on('connect', function() {
      var stream = ss.createStream();
      ss(socket)
        .emit('echo', stream, { hi: 1 })
        .on('echo', function(stream, obj) {
          expect(obj).to.eql({ hi: 1 });

          var data = '';
          stream.on('readable', function() {
            var chunk;
            while (null !== (chunk = stream.read())) {
              data += chunk;
            }
          }).on('end', function() {
            expect(data).to.equal('foobar');
            socket.disconnect();
            done();
          });
        });

      stream.write('foo');
      stream.write('bar');
      stream.end();
    });
  });

  it('should send/receive data through a same stream', function(done) {
    var socket = client();
    socket.on('connect', function() {
      var stream = ss.createStream({ allowHalfOpen: true });
      ss(socket).emit('sendBack', stream);
      stream.write('foo');
      stream.write('bar');
      stream.end();

      var data = '';
      stream.on('data', function(chunk) {
        data += chunk;
      }).on('end', function() {
        expect(data).to.equal('foobar');
        socket.disconnect();
        done();
      });
    });
  });

  it('should handle multiple streams', function(done) {
    var socket = client();
    socket.on('connect', function() {
      var stream1 = ss.createStream();
      var stream2 = ss.createStream();
      ss(socket).emit('multi', stream1, stream2);
      stream1.write('foo');
      stream1.write('bar');
      stream1.end();

      var data = '';
      stream2.on('data', function(chunk) {
        data += chunk;
      }).on('end', function() {
        expect(data).to.equal('foobar');
        socket.disconnect();
        done();
      });
    });
  });

  it('should send an error happened on the client', function(done) {
    var socket = client();
    socket.on('connect', function() {
      var stream = ss.createStream();
      ss(socket).emit('clientError', stream, function(msg) {
        expect(msg).to.equal('error on the client');
        done()
      });
      stream.emit('error', new Error('error on the client'));
    });
  });

  it('should receive an error happened on the server', function(done) {
    var socket = client();
    socket.on('connect', function() {
      var stream = ss.createStream();
      ss(socket).emit('serverError', stream, 'error on the server');
      stream.on('error', function(err) {
        expect(err.message).to.equal('error on the server');
        done()
      });
    });
  });

  if (Blob) {
    describe('BlobReadStream', function() {
      it('should read blob', function(done) {
        var socket = client();
        socket.on('connect', function() {
          var stream = ss.createStream();
          ss(socket)
            .emit('echo', stream)
            .on('echo', function(stream) {
              var data = '';
              stream.on('data', function(chunk) {
                data += chunk;
              }).on('end', function() {
                expect(data).to.equal('foobar');
                socket.disconnect();
                done();
              });
            });
          ss.createBlobReadStream(new Blob(['foo', 'bar'])).pipe(stream);
        });
      });
    });
  }
});

<commit_msg>add a test for Buffer<commit_after>var expect = require('expect.js');
var Blob = require('blob');
var ss = require('../');
var support = require('./support');
var client = support.client;

describe('socket.io-stream', function() {
  this.timeout(70000);

  it('should send/receive a file', function(done) {
    var sums = [];
    var socket = client();
    socket.on('connect', function() {
      var file = ss.createStream();
      ss(socket).emit('read', file, 'test/support/frog.jpg', function(sum) {
        check(sum);
      });

      var checksum = ss.createStream();
      ss(socket).emit('checksum', checksum, function(sum) {
        check(sum);
      });

      file.pipe(checksum);

      function check(sum) {
        sums.push(sum);
        if (sums.length < 2) return;
        expect(sums[0]).to.equal(sums[1]);
        socket.disconnect();
        done();
      }
    });
  });

  it('should send/receive data in flowing mode', function(done) {
    var socket = client();
    socket.on('connect', function() {
      var stream = ss.createStream();
      ss(socket)
        .emit('echo', stream, { hi: 1 })
        .on('echo', function(stream, obj) {
          expect(obj).to.eql({ hi: 1 });

          var data = '';
          stream.on('data', function(chunk) {
            data += chunk;
          }).on('end', function() {
            expect(data).to.equal('foobar');
            socket.disconnect();
            done();
          });
        });

      stream.write('foo');
      stream.write('bar');
      stream.end();
    });
  });

  it('should send/receive data in paused mode', function(done) {
    var socket = client();
    socket.on('connect', function() {
      var stream = ss.createStream();
      ss(socket)
        .emit('echo', stream, { hi: 1 })
        .on('echo', function(stream, obj) {
          expect(obj).to.eql({ hi: 1 });

          var data = '';
          stream.on('readable', function() {
            var chunk;
            while (null !== (chunk = stream.read())) {
              data += chunk;
            }
          }).on('end', function() {
            expect(data).to.equal('foobar');
            socket.disconnect();
            done();
          });
        });

      stream.write('foo');
      stream.write('bar');
      stream.end();
    });
  });

  it('should send/receive Buffer', function(done) {
    var socket = client();
    socket.on('connect', function() {
      var stream = ss.createStream();
      ss(socket)
        .emit('echo', stream)
        .on('echo', function(stream) {
          var buffers = [];
          stream.on('data', function(chunk) {
            buffers.push(chunk);
          }).on('end', function() {
            expect(Buffer.concat(buffers).equals(new Buffer([0, 1, 2, 3]))).to.be.ok();
            socket.disconnect();
            done();
          });
        });

      stream.write(new Buffer([0, 1]));
      stream.write(new Buffer([2, 3]));
      stream.end();
    });
  });

  it('should send/receive data through a same stream', function(done) {
    var socket = client();
    socket.on('connect', function() {
      var stream = ss.createStream({ allowHalfOpen: true });
      ss(socket).emit('sendBack', stream);
      stream.write('foo');
      stream.write('bar');
      stream.end();

      var data = '';
      stream.on('data', function(chunk) {
        data += chunk;
      }).on('end', function() {
        expect(data).to.equal('foobar');
        socket.disconnect();
        done();
      });
    });
  });

  it('should handle multiple streams', function(done) {
    var socket = client();
    socket.on('connect', function() {
      var stream1 = ss.createStream();
      var stream2 = ss.createStream();
      ss(socket).emit('multi', stream1, stream2);
      stream1.write('foo');
      stream1.write('bar');
      stream1.end();

      var data = '';
      stream2.on('data', function(chunk) {
        data += chunk;
      }).on('end', function() {
        expect(data).to.equal('foobar');
        socket.disconnect();
        done();
      });
    });
  });

  it('should send an error happened on the client', function(done) {
    var socket = client();
    socket.on('connect', function() {
      var stream = ss.createStream();
      ss(socket).emit('clientError', stream, function(msg) {
        expect(msg).to.equal('error on the client');
        done()
      });
      stream.emit('error', new Error('error on the client'));
    });
  });

  it('should receive an error happened on the server', function(done) {
    var socket = client();
    socket.on('connect', function() {
      var stream = ss.createStream();
      ss(socket).emit('serverError', stream, 'error on the server');
      stream.on('error', function(err) {
        expect(err.message).to.equal('error on the server');
        done()
      });
    });
  });

  if (Blob) {
    describe('BlobReadStream', function() {
      it('should read blob', function(done) {
        var socket = client();
        socket.on('connect', function() {
          var stream = ss.createStream();
          ss(socket)
            .emit('echo', stream)
            .on('echo', function(stream) {
              var data = '';
              stream.on('data', function(chunk) {
                data += chunk;
              }).on('end', function() {
                expect(data).to.equal('foobar');
                socket.disconnect();
                done();
              });
            });
          ss.createBlobReadStream(new Blob(['foo', 'bar'])).pipe(stream);
        });
      });
    });
  }
});

<|endoftext|>


<commit_before>
var chai = require("chai");
var chaiAsPromised = require("chai-as-promised");

chai.use(chaiAsPromised);
chai.should();

var rdb = require("rethinkdb");
var _ = require("lodash");

var moment = require("moment");
var testUtils = require("./test_utils");

after(function(){
  return testUtils.closeConnection();
});

describe("Correction methods", function(){
  var test = {db:null,cleanup:null,load:null};
  // setup a new fresh database for every test!
  beforeEach(testUtils.beforeTest(test));
  // remove the DB after each test
  afterEach(testUtils.afterTest(test));

  it("should return the number of pending corrections", function(){
    return test.load({Solutions:
      [
        {exercise: 1, group: 1, results:["stuff"]},
        {exercise: 1, group: 2},
        {exercise: 2, group: 1},
        {exercise: 2, group: 2}
      ]
    }).then(function(){
      return test.db.Corrections.getNumPending(1).then(function(pending){
        pending.should.equal(1);
      });
    });
  });
  it("lists all pending corrections for a tutor", function(){
    return test.load({Solutions:[{id: 1, lock:"tutor",inProcess:true},{id: 2, lock:"tutor"},{id: 3, lock:"tutor", inProcess:false}]})
    .then(function(){
      return test.db.Corrections.getUnfinishedSolutionsForTutor("tutor").then(function(sol){
        sol.should.have.length(1);
        sol[0].id.should.equal(1);
      });
    });
  });
  it("lists all finished solutions for a tutor", function () {
    return test.load({
      Solutions: [
        {id: 1, lock:"tutor",inProcess:true},
        {id: 2, lock:"tutor"},
        {id: 3, lock:"tutor",inProcess:false}
      ]})
    .then(function() {
      return test.db.Corrections.getFinishedSolutionsForTutor("tutor").then(function(sol) {
        sol.should.have.length(1);
        sol[0].id.should.equal(3);
      });
    });
  });
  it("can list all solutions for an exercise", function(){
    return test.load({Solutions:[
      {exercise: 1, group: 1},
      {exercise: 1, group: 2},
      {exercise: 2, group: 1},
      {exercise: 2, group: 2}
    ]}).then(function(){
      return test.db.Corrections.getSolutionsForExercise(1).then(function(sols){
        sols.should.have.length(2);
        bareSols = _.map(sols, function(s) { delete s.id; return s });
        bareSols.should.deep.include.members([{exercise: 1, group: 1},{exercise: 1, group: 2}]);
      });
    });
  });
  /*
  it("should be possible to store results for a locked solution", function(){
    return test.load({Solutions:[{id:1, lock:"tutor"}]})
    .then(function(){
      return test.db.Corrections.setResultForExercise("tutor",1,["res"]).then(function(){
        return test.db.Corrections.getResultForExercise(1).then(function(sol){
          (sol == null).should.be.false;
          sol.result.should.deep.equal(["res"]);
        })
      });
    });
  });
  */
  it("should not be possibe to lock more than 10 solutions by a single tutor", function() {
    return test.load(
      {Solutions: [
        {exercise: 1, id:1, lock:"Hans", inProcess: false},
        {exercise: 1, id:2, lock:"Hans", inProcess: true},
        {exercise: 1, id:3, lock:"Hans", inProcess: true},
        {exercise: 1, id:4, lock:"Hans", inProcess: false},
        {exercise: 1, id:5, lock:"Hans", inProcess: true},
        {exercise: 1, id:6, lock:"Hans", inProcess: true},
        {exercise: 1, id:7, lock:"Hans", inProcess: true},
        {exercise: 1, id:8, lock:"Hans", inProcess: true},
        {exercise: 1, id:9, lock:"Hans", inProcess: true},
        {exercise: 1, id:10, lock:"Hans", inProcess: true},
        {exercise: 1, id:12, lock:"Hans", inProcess: true},
        {exercise: 1, id:13, lock:"Hans", inProcess: true},
        {exercise: 1, id:14, lock:"Hans", inProcess: true},
        {exercise: 1, id:11}, {exercise: 1, id:12}],
       Tutors: [{name: "Hans"}]})
    .then(function() {
      return test.db.Corrections.lockNextSolutionForTutor("Hans", 1).should.be.rejected;
    });
  });
  it("should create a time stamp when locking a solution", function () {
    return test.load({Solutions: [{exercise: 1, group: 2}]})
    .then(function() {
      return test.db.Corrections.lockNextSolutionForTutor("tutor", 1).then(function(sol) {
        sol.should.have.property("lockTimeStamp");
      });
    });
  });
  //---------------------------------------------------------------------
  // Locks
  //---------------------------------------------------------------------
  it("should not be possible to store results for a not locked solution", function(){
    return test.load({Solutions:[{id:1}]})
    .then(function(){
      return test.db.Corrections.setResultForExercise("tutor",1,["res"]).should.be.rejected;
    });
  });
  it("should not be possible to store results for a solution locked by another tutor", function(){
    return test.load({Solutions:[{id:1, lock:"tutor2"}]})
    .then(function(){
      return test.db.Corrections.setResultForExercise("tutor",1,["res"]).should.be.rejected;
    });
  });
  it("should lock a solution for a tutor", function(){
    return test.load({Solutions: [{id:1,exercise:1, group:1},{exercise:2,group:2}]})
    .then(function(){
      return test.db.Corrections.lockSolutionForTutor("tutor",1).should.be.fulfilled;
    });
  });
  it("locking a solution twice should have no effect", function(){
    return test.load({Solutions: [{id:1,exercise:1, group:1},{exercise:2,group:2}]})
    .then(function(){
      return test.db.Corrections.lockSolutionForTutor("tutor",1).then(function(){
        return test.db.Corrections.lockSolutionForTutor("tutor",1);
      }).should.be.fulfilled;
    })
  });
  it("should not be able to lock a solution by two different tutors", function(){
    return test.load({Solutions: [{id:1,exercise:1, group:1},{exercise:2,group:2}]})
    .then(function(){
      return test.db.Corrections.lockSolutionForTutor("tutor",1).then(function(){
        return test.db.Corrections.lockSolutionForTutor("tutor2",1)
      }).should.be.rejected;
    });
  });
  it("solutions with results cannot be locked", function(){
    return test.load({Solutions: [{id:1,exercise:1, group:1,results:[]},{exercise:2,group:2}]})
    .then(function(){
      return test.db.Corrections.lockSolutionForTutor("tutor",1).should.be.rejected;
    });
  });
  //---------------------------------------------------------------------
  it("should lock a random not corrected solution", function(){
    return test.load({Solutions: [{exercise:1, group:1, results:[]},{exercise:1,group:2}]})
    .then(function(){
      return test.db.Corrections.lockNextSolutionForTutor("tutor",1).then(function(){
        return test.db.Corrections.getSolutionsForGroup(2).then(function(sol){
          sol[0].lock.should.equal("tutor");
        });
      });
    });
  });
  it("should mark a newly locked solution as 'inProcess'", function(){
    return test.load({Solutions: [{exercise:1,group:2}]})
    .then(function(){
      return test.db.Corrections.lockNextSolutionForTutor("tutor",1).then(function(sol){
        sol.inProcess.should.be.true;
      });
    });
  });
  it("should fail if no exercise could be locked", function(){
    return test.load({Solutions: [{exercise:1, group:1, result:[]},{exercise:2,group:2}]})
    .then(function(){
      return test.db.Corrections.lockNextSolutionForTutor("tutor",3).then(function(res){
        (res === undefined).should.be.true;
      });
    });
  });
  it("should finalize a solution by setting the 'inProcess' marker to false", function(){
    return test.load({Solutions: [{id:1,results:[],lock:"tutor",inProcess:true}]})
    .then(function(){
      return test.db.Corrections.finishSolution("tutor",1).then(function(){
        return test.db.Corrections.getUnfinishedSolutionsForTutor("tutor").then(function(sols){
          sols.should.have.length(0);
        });
      });
    });
  });

  it("should not finalize a solution of another tutor", function(){
    return test.load({Solutions: [{id:1,results:[],lock:"tutor",inProcess:true}]})
    .then(function(){
      return test.db.Corrections.finishSolution("tutor2",1).should.be.rejected;
    });
  });

  it("should not finalize a solution without results", function(){
    return test.load({Solutions: [{id:1,lock:"tutor",inProcess:true}]})
    .then(function(){
      return test.db.Corrections.finishSolution("tutor2",1).should.be.rejected;
    });
  });

  it("should list all unfinished exercises for a tutor", function(){
    return test.load({Solutions: [{id:1,lock:"tutor",inProcess:true},{id:1,lock:"tutor",inProcess:false}]})
    .then(function(){
      return test.db.Corrections.getUnfinishedSolutionsForTutor("tutor").then(function(sols){
        sols.should.have.length(1);
      });
    });
  });
  it("can get a solution by id", function(){
    return test.load({Solutions: [{id:1}]})
    .then(function(){
      return test.db.Corrections.getSolutionById(1).then(function(s){
        s.id.should.equal(1);
      });
    });
  });

  it("has a method returning the correction status of all exercises", function(){
    var date = moment().subtract(1, "days").toJSON();
    return test.load({Solutions:[
      {exercise: 1, group: 1, results:[],lock: "tutor",inProcess:false},
      {exercise: 1, group: 2},
      {exercise: 2, group: 1, lock:"blubb",inProcess:true},
      {exercise: 2, group: 2}
    ],Exercises:[
      {id: 1, activationDate: rdb.ISO8601(date)},
      {id: 2, activationDate: rdb.ISO8601(date)}
    ],Tutors: [
      {name:"tutor", contingent:1}
    ]})
    .then(function(){
      return test.db.Corrections.getStatus("tutor").then(function(status){
        status.should.have.length(2);
        bareStatus = _.map(status, function(s) { delete s.id; delete s.exercise.activationDate; return s });
        bareStatus.should.deep.include.members([
          {
            exercise:{id: 1},
            should: 2,
            is: 1,
            solutions:2,corrected:1,locked:1
          },
          {
            exercise:{id: 2},
            should: 2,
            is: 0,
            solutions:2,corrected:0,locked:1
          }]);
      });
    });
  });

  it("returns only queried unfinished exercises", function() {
    return test.load({Solutions: [{id:1,exercise:1,lock:"tutor",inProcess:true},
                                  {id:2,lock:"tutor",inProcess:false}]})
    .then(function() {
      return test.db.Corrections.getUnfinishedSolutionsForTutor("tutor").then(function(sols){
        sols.should.have.length(1);
      });
    });
  });

  it("has a method that lists all solutions of a user", function(){
    return test.load({Solutions: [{id:1,group:1,exercise:1}],
                      Groups: [{id:1,users:[2],pendingUsers:[]}],
                      Users: [{id:2, pseudonym:"A"}]})
    .then(function() {
      return test.db.Corrections.getUserSolutions(2).then(function(sols){
        sols.should.have.length(1);
        sols.should.deep.include.members([{id:1,group:1,exercise:1}]);
      });
    });
  });

  it("can calculate the contingent for an exercise and tutor", function(){
    return test.load({Tutors:[{name:"a",contingent:20},{name:"b",contingent:10}],
      Solutions:[{exercise:1},{exercise:1,lock:"a",inProcess:false},{exercise:1},{exercise:2}]
    })
    .then(function(){
      return test.db.Corrections.getExerciseContingentForTutor("a",1).then(function(contingent){
        contingent.should.should.equal(2);
        contingent.is.should.equal(1);
      });
    });
  });

  it("can get a specific solution for a user", function(){
    return test.load({Solutions: [{id:1,group:1,exercise:1},{id:2,group:1,exercise:2},{id:3,group:2,exercise:2}],
              Groups: [{id:1,users:[2], pendingUsers:[]}],
              Users: [{id:2,pseudonym:"B"}]})
    .then(function(){
      return test.db.Corrections.getUserExerciseSolution(2,2).then(function(sols){
        sols.id.should.equal(2);
      });
    });
  });
  /**/
});
<commit_msg>Added test for hasPdf function.<commit_after>
var chai = require("chai");
var chaiAsPromised = require("chai-as-promised");

chai.use(chaiAsPromised);
chai.should();

var rdb = require("rethinkdb");
var _ = require("lodash");

var moment = require("moment");
var testUtils = require("./test_utils");

after(function(){
  return testUtils.closeConnection();
});

describe("Correction methods", function(){
  var test = {db:null,cleanup:null,load:null};
  // setup a new fresh database for every test!
  beforeEach(testUtils.beforeTest(test));
  // remove the DB after each test
  afterEach(testUtils.afterTest(test));

  it("should return the number of pending corrections", function(){
    return test.load({Solutions:
      [
        {exercise: 1, group: 1, results:["stuff"]},
        {exercise: 1, group: 2},
        {exercise: 2, group: 1},
        {exercise: 2, group: 2}
      ]
    }).then(function(){
      return test.db.Corrections.getNumPending(1).then(function(pending){
        pending.should.equal(1);
      });
    });
  });
  it("should return the processed flag", function() {
    return test.load({
      Solutions: [
        {id: 0, processed: false},
        {id: 1, processed: true}
      ]
    }).then(function() {
      return test.db.Corrections.hasPdf(0).then(function(has) {
        has.should.equal(false);
        return test.db.Corrections.hasPdf(1).then(function(has2) {
          has2.should.equal(true);
        });
      });
    });
  });
  it("lists all pending corrections for a tutor", function(){
    return test.load({Solutions:[{id: 1, lock:"tutor",inProcess:true},{id: 2, lock:"tutor"},{id: 3, lock:"tutor", inProcess:false}]})
    .then(function(){
      return test.db.Corrections.getUnfinishedSolutionsForTutor("tutor").then(function(sol){
        sol.should.have.length(1);
        sol[0].id.should.equal(1);
      });
    });
  });
  it("lists all finished solutions for a tutor", function () {
    return test.load({
      Solutions: [
        {id: 1, lock:"tutor",inProcess:true},
        {id: 2, lock:"tutor"},
        {id: 3, lock:"tutor",inProcess:false}
      ]})
    .then(function() {
      return test.db.Corrections.getFinishedSolutionsForTutor("tutor").then(function(sol) {
        sol.should.have.length(1);
        sol[0].id.should.equal(3);
      });
    });
  });
  it("can list all solutions for an exercise", function(){
    return test.load({Solutions:[
      {exercise: 1, group: 1},
      {exercise: 1, group: 2},
      {exercise: 2, group: 1},
      {exercise: 2, group: 2}
    ]}).then(function(){
      return test.db.Corrections.getSolutionsForExercise(1).then(function(sols){
        sols.should.have.length(2);
        bareSols = _.map(sols, function(s) { delete s.id; return s });
        bareSols.should.deep.include.members([{exercise: 1, group: 1},{exercise: 1, group: 2}]);
      });
    });
  });
  /*
  it("should be possible to store results for a locked solution", function(){
    return test.load({Solutions:[{id:1, lock:"tutor"}]})
    .then(function(){
      return test.db.Corrections.setResultForExercise("tutor",1,["res"]).then(function(){
        return test.db.Corrections.getResultForExercise(1).then(function(sol){
          (sol == null).should.be.false;
          sol.result.should.deep.equal(["res"]);
        })
      });
    });
  });
  */
  it("should not be possibe to lock more than 10 solutions by a single tutor", function() {
    return test.load(
      {Solutions: [
        {exercise: 1, id:1, lock:"Hans", inProcess: false},
        {exercise: 1, id:2, lock:"Hans", inProcess: true},
        {exercise: 1, id:3, lock:"Hans", inProcess: true},
        {exercise: 1, id:4, lock:"Hans", inProcess: false},
        {exercise: 1, id:5, lock:"Hans", inProcess: true},
        {exercise: 1, id:6, lock:"Hans", inProcess: true},
        {exercise: 1, id:7, lock:"Hans", inProcess: true},
        {exercise: 1, id:8, lock:"Hans", inProcess: true},
        {exercise: 1, id:9, lock:"Hans", inProcess: true},
        {exercise: 1, id:10, lock:"Hans", inProcess: true},
        {exercise: 1, id:12, lock:"Hans", inProcess: true},
        {exercise: 1, id:13, lock:"Hans", inProcess: true},
        {exercise: 1, id:14, lock:"Hans", inProcess: true},
        {exercise: 1, id:11}, {exercise: 1, id:12}],
       Tutors: [{name: "Hans"}]})
    .then(function() {
      return test.db.Corrections.lockNextSolutionForTutor("Hans", 1).should.be.rejected;
    });
  });
  it("should create a time stamp when locking a solution", function () {
    return test.load({Solutions: [{exercise: 1, group: 2}]})
    .then(function() {
      return test.db.Corrections.lockNextSolutionForTutor("tutor", 1).then(function(sol) {
        sol.should.have.property("lockTimeStamp");
      });
    });
  });
  //---------------------------------------------------------------------
  // Locks
  //---------------------------------------------------------------------
  it("should not be possible to store results for a not locked solution", function(){
    return test.load({Solutions:[{id:1}]})
    .then(function(){
      return test.db.Corrections.setResultForExercise("tutor",1,["res"]).should.be.rejected;
    });
  });
  it("should not be possible to store results for a solution locked by another tutor", function(){
    return test.load({Solutions:[{id:1, lock:"tutor2"}]})
    .then(function(){
      return test.db.Corrections.setResultForExercise("tutor",1,["res"]).should.be.rejected;
    });
  });
  it("should lock a solution for a tutor", function(){
    return test.load({Solutions: [{id:1,exercise:1, group:1},{exercise:2,group:2}]})
    .then(function(){
      return test.db.Corrections.lockSolutionForTutor("tutor",1).should.be.fulfilled;
    });
  });
  it("locking a solution twice should have no effect", function(){
    return test.load({Solutions: [{id:1,exercise:1, group:1},{exercise:2,group:2}]})
    .then(function(){
      return test.db.Corrections.lockSolutionForTutor("tutor",1).then(function(){
        return test.db.Corrections.lockSolutionForTutor("tutor",1);
      }).should.be.fulfilled;
    })
  });
  it("should not be able to lock a solution by two different tutors", function(){
    return test.load({Solutions: [{id:1,exercise:1, group:1},{exercise:2,group:2}]})
    .then(function(){
      return test.db.Corrections.lockSolutionForTutor("tutor",1).then(function(){
        return test.db.Corrections.lockSolutionForTutor("tutor2",1)
      }).should.be.rejected;
    });
  });
  it("solutions with results cannot be locked", function(){
    return test.load({Solutions: [{id:1,exercise:1, group:1,results:[]},{exercise:2,group:2}]})
    .then(function(){
      return test.db.Corrections.lockSolutionForTutor("tutor",1).should.be.rejected;
    });
  });
  //---------------------------------------------------------------------
  it("should lock a random not corrected solution", function(){
    return test.load({Solutions: [{exercise:1, group:1, results:[]},{exercise:1,group:2}]})
    .then(function(){
      return test.db.Corrections.lockNextSolutionForTutor("tutor",1).then(function(){
        return test.db.Corrections.getSolutionsForGroup(2).then(function(sol){
          sol[0].lock.should.equal("tutor");
        });
      });
    });
  });
  it("should mark a newly locked solution as 'inProcess'", function(){
    return test.load({Solutions: [{exercise:1,group:2}]})
    .then(function(){
      return test.db.Corrections.lockNextSolutionForTutor("tutor",1).then(function(sol){
        sol.inProcess.should.be.true;
      });
    });
  });
  it("should fail if no exercise could be locked", function(){
    return test.load({Solutions: [{exercise:1, group:1, result:[]},{exercise:2,group:2}]})
    .then(function(){
      return test.db.Corrections.lockNextSolutionForTutor("tutor",3).then(function(res){
        (res === undefined).should.be.true;
      });
    });
  });
  it("should finalize a solution by setting the 'inProcess' marker to false", function(){
    return test.load({Solutions: [{id:1,results:[],lock:"tutor",inProcess:true}]})
    .then(function(){
      return test.db.Corrections.finishSolution("tutor",1).then(function(){
        return test.db.Corrections.getUnfinishedSolutionsForTutor("tutor").then(function(sols){
          sols.should.have.length(0);
        });
      });
    });
  });

  it("should not finalize a solution of another tutor", function(){
    return test.load({Solutions: [{id:1,results:[],lock:"tutor",inProcess:true}]})
    .then(function(){
      return test.db.Corrections.finishSolution("tutor2",1).should.be.rejected;
    });
  });

  it("should not finalize a solution without results", function(){
    return test.load({Solutions: [{id:1,lock:"tutor",inProcess:true}]})
    .then(function(){
      return test.db.Corrections.finishSolution("tutor2",1).should.be.rejected;
    });
  });

  it("should list all unfinished exercises for a tutor", function(){
    return test.load({Solutions: [{id:1,lock:"tutor",inProcess:true},{id:1,lock:"tutor",inProcess:false}]})
    .then(function(){
      return test.db.Corrections.getUnfinishedSolutionsForTutor("tutor").then(function(sols){
        sols.should.have.length(1);
      });
    });
  });
  it("can get a solution by id", function(){
    return test.load({Solutions: [{id:1}]})
    .then(function(){
      return test.db.Corrections.getSolutionById(1).then(function(s){
        s.id.should.equal(1);
      });
    });
  });

  it("has a method returning the correction status of all exercises", function(){
    var date = moment().subtract(1, "days").toJSON();
    return test.load({Solutions:[
      {exercise: 1, group: 1, results:[],lock: "tutor",inProcess:false},
      {exercise: 1, group: 2},
      {exercise: 2, group: 1, lock:"blubb",inProcess:true},
      {exercise: 2, group: 2}
    ],Exercises:[
      {id: 1, activationDate: rdb.ISO8601(date)},
      {id: 2, activationDate: rdb.ISO8601(date)}
    ],Tutors: [
      {name:"tutor", contingent:1}
    ]})
    .then(function(){
      return test.db.Corrections.getStatus("tutor").then(function(status){
        status.should.have.length(2);
        bareStatus = _.map(status, function(s) { delete s.id; delete s.exercise.activationDate; return s });
        bareStatus.should.deep.include.members([
          {
            exercise:{id: 1},
            should: 2,
            is: 1,
            solutions:2,corrected:1,locked:1
          },
          {
            exercise:{id: 2},
            should: 2,
            is: 0,
            solutions:2,corrected:0,locked:1
          }]);
      });
    });
  });

  it("returns only queried unfinished exercises", function() {
    return test.load({Solutions: [{id:1,exercise:1,lock:"tutor",inProcess:true},
                                  {id:2,lock:"tutor",inProcess:false}]})
    .then(function() {
      return test.db.Corrections.getUnfinishedSolutionsForTutor("tutor").then(function(sols){
        sols.should.have.length(1);
      });
    });
  });

  it("has a method that lists all solutions of a user", function(){
    return test.load({Solutions: [{id:1,group:1,exercise:1}],
                      Groups: [{id:1,users:[2],pendingUsers:[]}],
                      Users: [{id:2, pseudonym:"A"}]})
    .then(function() {
      return test.db.Corrections.getUserSolutions(2).then(function(sols){
        sols.should.have.length(1);
        sols.should.deep.include.members([{id:1,group:1,exercise:1}]);
      });
    });
  });

  it("can calculate the contingent for an exercise and tutor", function(){
    return test.load({Tutors:[{name:"a",contingent:20},{name:"b",contingent:10}],
      Solutions:[{exercise:1},{exercise:1,lock:"a",inProcess:false},{exercise:1},{exercise:2}]
    })
    .then(function(){
      return test.db.Corrections.getExerciseContingentForTutor("a",1).then(function(contingent){
        contingent.should.should.equal(2);
        contingent.is.should.equal(1);
      });
    });
  });

  it("can get a specific solution for a user", function(){
    return test.load({Solutions: [{id:1,group:1,exercise:1},{id:2,group:1,exercise:2},{id:3,group:2,exercise:2}],
              Groups: [{id:1,users:[2], pendingUsers:[]}],
              Users: [{id:2,pseudonym:"B"}]})
    .then(function(){
      return test.db.Corrections.getUserExerciseSolution(2,2).then(function(sols){
        sols.id.should.equal(2);
      });
    });
  });
  /**/
});
<|endoftext|>


<commit_before>/* Copyright (c) 2017 e-soa Jacques Desodt, MIT License */
'use strict'

/* Default plugin options */
const role = 'entity-crud-test'

/* Prerequisites */
const Seneca = require('seneca') // eslint-disable-line no-unused-vars
const testFunctions = require('./functions')

/* Test prerequisites */
const Code = require('code')
const Lab = require('lab', {timeout: testFunctions.timeout})
var lab = (exports.lab = Lab.script())
var describe = lab.describe
var it = lab.it
var expect = Code.expect

describe('count', function () {
  //
  // Simple
  it('all', function (fin) {
    // Gets the Seneca instance
    var seneca = testFunctions.setSeneca(Seneca, role, fin) // Add 'print' for debug
    // Creates posts
    testFunctions.createPosts(seneca, role, function (results) {
      // Retrieves all data
      seneca.act({role: role, cmd: 'count'}, function (ignore, result) {
        // Checks result
        expect(result.success).to.equal(true)
        expect(result.count).to.equal(testFunctions.getPosts().length)
        fin()
      })
    })
  })

  // Select on field
  it('count title', function (fin) {
    /* Initializes */
    var title = 'Tuesday'
    // Gets the Seneca instance
    var seneca = testFunctions.setSeneca(Seneca, role, fin) // Add 'print' for debug
    // Creates posts
    testFunctions.createPosts(seneca, role, function (results) {
      // Retrieves all data
      seneca.act({role: role, cmd: 'count', select: {title: title}}, function (ignore, result) {
        // Checks result
        expect(result.success).to.equal(true)
        expect(result.count).to.equal(testFunctions.getTitleCount(title))
        fin()
      })
    })
  })

  // Deep count
  it('deep count', function (fin) {
    // Initializes
    var zipcode = '59491'
    // Gets the Seneca instance
    var seneca = testFunctions.setSeneca(Seneca, role, fin) // Add 'print' for debug
    // Creates posts
    testFunctions.createPosts(seneca, role, function (results) {
      // Retrieves all data
      seneca.act({
        role: role,
        cmd: 'count',
        deepselect: [{ property: 'data.zipcode', value: zipcode }]},
        function (ignore, result) {
          // Checks result
          expect(result.success).to.equal(true)
          expect(result.count).to.equal(testFunctions.getZipcodeCount(zipcode))
          // Another test which return no data
          // Retrieves all data
          seneca.act({
            role: role,
            cmd: 'count',
            select: {title: 'Monday'},
            deepselect: [{property: 'data.zipcode', value: zipcode}]},
            function (ignore, result) {
              // Checks result
              expect(result.success).to.equal(true)
              expect(result.count).to.equal(0)
              fin()
            })
        })
    })
  })
  //
})
<commit_msg>This project has been moved to GitLab<commit_after><|endoftext|>


<commit_before>describe("Essential.Core#crawl", function() {
  context("given six associated behaviors in the rootElement", function() {

    beforeEach(function() {
      setDocumentContents("test/fixtures/basic_structure.html");
      this.crawledContent = Essential.Core.crawl(document);
    });

    it("must return an object with six keys", function() {
      expect(this.crawledContent).to.be.an("Object");
      expect(Object.keys(this.crawledContent).length).to.eql(6);
    });

    it("every key of the object must have the name of the associated behavior", function() {
      expect(Object.keys(this.crawledContent)).to.eql(
        ["test", "test-inner", "multiple1", "multiple2", "test2", "test-inner2"]
      );
    });

    it("must allow multiple behaviors attached on the same element", function() {
      expect(Object.keys(this.crawledContent)).to.include("multiple1");
      expect(Object.keys(this.crawledContent)).to.include("multiple2");
    });

    it("only search for behaviors contained in the rootElement", function() {
      var rootElement = document.getElementsByTagName("section")[0],
        crawledContent = Essential.Core.crawl(rootElement);

      expect(Object.keys(crawledContent)).to.eql(
        ["test-inner", "multiple1", "multiple2"]
      );
    });
  });

  context("given no associated behaviors in the rootElement", function() {

    it("must return an empty object", function() {
      setDocumentContents("test/fixtures/page_without_behaviors.html");
      var crawledContent = Essential.Core.crawl(document);

      expect(crawledContent).to.be.an("Object");
      expect(Object.keys(crawledContent).length).to.be.eql(0);
    });
  });

  context("given a behavior associated to multiple elements", function() {
    beforeEach(function() {
      setDocumentContents("test/fixtures/repeated_behavior.html");
      this.crawledContent = Essential.Core.crawl(document);
    });

    it("must return an object with the correct number of keys", function() {
      expect(Object.keys(this.crawledContent).length).to.be.eq(1);
    });

    it("must return an object with the correct key names", function() {
      expect(Object.keys(this.crawledContent)[0]).to.be.eq("carousel");
    });

    it("must return an object with an array of elements as a value", function() {
      expect(Array.isArray(this.crawledContent["carousel"])).to.be.eq(true);
    });

    it("must return an object with the correct values in every key", function() {
      var firstCarousel = document.getElementById("first-carousel"),
        secondCarousel = document.getElementById("second-carousel");

      expect(this.crawledContent["carousel"]).to.include(firstCarousel);
      expect(this.crawledContent["carousel"]).to.include(secondCarousel);
    });
  });
});
<commit_msg>Test suite improvments: changes a message in the Essential.Core#crawl function<commit_after>describe("Essential.Core#crawl", function() {
  context("given six associated behaviors in the rootElement", function() {

    beforeEach(function() {
      setDocumentContents("test/fixtures/basic_structure.html");
      this.crawledContent = Essential.Core.crawl(document);
    });

    it("must return an object with six keys", function() {
      expect(this.crawledContent).to.be.an("Object");
      expect(Object.keys(this.crawledContent).length).to.eql(6);
    });

    it("must return an object with the name of the associated behaviors as keys", function() {
      expect(Object.keys(this.crawledContent)).to.eql(
        ["test", "test-inner", "multiple1", "multiple2", "test2", "test-inner2"]
      );
    });

    it("must allow multiple behaviors attached on the same element", function() {
      expect(Object.keys(this.crawledContent)).to.include("multiple1");
      expect(Object.keys(this.crawledContent)).to.include("multiple2");
    });

    it("only search for behaviors contained in the rootElement", function() {
      var rootElement = document.getElementsByTagName("section")[0],
        crawledContent = Essential.Core.crawl(rootElement);

      expect(Object.keys(crawledContent)).to.eql(
        ["test-inner", "multiple1", "multiple2"]
      );
    });
  });

  context("given no associated behaviors in the rootElement", function() {

    it("must return an empty object", function() {
      setDocumentContents("test/fixtures/page_without_behaviors.html");
      var crawledContent = Essential.Core.crawl(document);

      expect(crawledContent).to.be.an("Object");
      expect(Object.keys(crawledContent).length).to.be.eql(0);
    });
  });

  context("given a behavior associated to multiple elements", function() {
    beforeEach(function() {
      setDocumentContents("test/fixtures/repeated_behavior.html");
      this.crawledContent = Essential.Core.crawl(document);
    });

    it("must return an object with the correct number of keys", function() {
      expect(Object.keys(this.crawledContent).length).to.be.eq(1);
    });

    it("must return an object with the correct key names", function() {
      expect(Object.keys(this.crawledContent)[0]).to.be.eq("carousel");
    });

    it("must return an object with an array of elements as a value", function() {
      expect(Array.isArray(this.crawledContent["carousel"])).to.be.eq(true);
    });

    it("must return an object with the correct values in every key", function() {
      var firstCarousel = document.getElementById("first-carousel"),
        secondCarousel = document.getElementById("second-carousel");

      expect(this.crawledContent["carousel"]).to.include(firstCarousel);
      expect(this.crawledContent["carousel"]).to.include(secondCarousel);
    });
  });
});
<|endoftext|>


<commit_before>//Require the dev-dependencies
let chai = require('chai');
let chaiHttp = require('chai-http');
let server = require('../dist/index').default;
chai.should();
let geojsonValidation = require('geojson-validation');

chai.use(chaiHttp);

function random(min, max) {
    min = Math.ceil(min);
    max = Math.floor(max);
    return Math.floor(Math.random() * (max - min + 1)) + min;
}
var randomLimit = random(25, 200);

describe('Departures', () => {
    describe('GET /StopPoint/Departures/200405035', () => {
        it('should get 10 departures from "Luxembourg, Gare Centrale"', (done) => {
            chai.request(server)
                .get('/StopPoint/Departures/200405035')
                .end((err, res) => {
                    res.should.have.status(200);
                    res.should.be.json;
                    res.body.should.be.a('array');
                    res.body.length.should.be.equal(10);
                    for(var i = 0; i < res.body.length; i++) {
                        var departure = res.body[i];
                        departure.type.should.be.a('String');
                        if (departure.trainId !== null) {
                            departure.trainId.should.be.a('String');
                        }
                        departure.line.should.be.a('String');
                        departure.number.should.be.a('Number');
                        departure.departure.should.be.a('Number');
                        departure.delay.should.be.a('Number');
                        departure.live.should.be.a('Boolean');
                        departure.destination.should.be.a('String');
                        if (departure.destinationId !== null) {
                            departure.destinationId.should.be.a('Number');
                        }
                    }
                    done();
                });
        });
    });
    describe('GET /StopPoint/Departures/200405035/'+randomLimit, () => {
        it('should get a random number ['+randomLimit+'] of departures from "Luxembourg, Gare Centrale"', (done) => {
            chai.request(server)
                .get('/StopPoint/Departures/200405035/'+randomLimit)
                .end((err, res) => {
                    res.should.have.status(200);
                    res.should.be.json;
                    res.body.should.be.a('array');
                    res.body.length.should.be.equal(randomLimit);
                    for(var i = 0; i < res.body.length; i++) {
                        var departure = res.body[i];
                        departure.type.should.be.a('String');
                        if (departure.trainId !== null) {
                            departure.trainId.should.be.a('String');
                        }
                        departure.line.should.be.a('String');
                        departure.number.should.be.a('Number');
                        departure.departure.should.be.a('Number');
                        departure.departureISO.should.be.a('String');
                        departure.delay.should.be.a('Number');
                        departure.live.should.be.a('Boolean');
                        departure.destination.should.be.a('String');
                        if (departure.destinationId !== null) {
                            departure.destinationId.should.be.a('Number');
                        }
                    }
                    done();
                });
        });
    });
});
<commit_msg>no geojson in departures (for now)<commit_after>//Require the dev-dependencies
let chai = require('chai');
let chaiHttp = require('chai-http');
let server = require('../dist/index').default;
chai.should();

chai.use(chaiHttp);

function random(min, max) {
    min = Math.ceil(min);
    max = Math.floor(max);
    return Math.floor(Math.random() * (max - min + 1)) + min;
}
var randomLimit = random(25, 200);

describe('Departures', () => {
    describe('GET /StopPoint/Departures/200405035', () => {
        it('should get 10 departures from "Luxembourg, Gare Centrale"', (done) => {
            chai.request(server)
                .get('/StopPoint/Departures/200405035')
                .end((err, res) => {
                    res.should.have.status(200);
                    res.should.be.json;
                    res.body.should.be.a('array');
                    res.body.length.should.be.equal(10);
                    for(var i = 0; i < res.body.length; i++) {
                        var departure = res.body[i];
                        departure.type.should.be.a('String');
                        if (departure.trainId !== null) {
                            departure.trainId.should.be.a('String');
                        }
                        departure.line.should.be.a('String');
                        departure.number.should.be.a('Number');
                        departure.departure.should.be.a('Number');
                        departure.delay.should.be.a('Number');
                        departure.live.should.be.a('Boolean');
                        departure.destination.should.be.a('String');
                        if (departure.destinationId !== null) {
                            departure.destinationId.should.be.a('Number');
                        }
                    }
                    done();
                });
        });
    });
    describe('GET /StopPoint/Departures/200405035/'+randomLimit, () => {
        it('should get a random number ['+randomLimit+'] of departures from "Luxembourg, Gare Centrale"', (done) => {
            chai.request(server)
                .get('/StopPoint/Departures/200405035/'+randomLimit)
                .end((err, res) => {
                    res.should.have.status(200);
                    res.should.be.json;
                    res.body.should.be.a('array');
                    res.body.length.should.be.equal(randomLimit);
                    for(var i = 0; i < res.body.length; i++) {
                        var departure = res.body[i];
                        departure.type.should.be.a('String');
                        if (departure.trainId !== null) {
                            departure.trainId.should.be.a('String');
                        }
                        departure.line.should.be.a('String');
                        departure.number.should.be.a('Number');
                        departure.departure.should.be.a('Number');
                        departure.departureISO.should.be.a('String');
                        departure.delay.should.be.a('Number');
                        departure.live.should.be.a('Boolean');
                        departure.destination.should.be.a('String');
                        if (departure.destinationId !== null) {
                            departure.destinationId.should.be.a('Number');
                        }
                    }
                    done();
                });
        });
    });
});
<|endoftext|>


<commit_before>'use strict';

var testUtils = require('./testUtils');
var chai = require('chai');
var stripe = require('../lib/stripe')(
  testUtils.getUserStripeKey(),
  'latest'
);

var expect = chai.expect;

var CUSTOMER_DETAILS = {
  description: 'Some customer',
  card: 'tok_visa',
};

var CURRENCY = '_DEFAULT_CURRENCY_NOT_YET_GOTTEN_';

describe('Flows', function() {
  // Note: These tests must be run as one so we can retrieve the
  // default_currency (required in subsequent tests);

  var cleanup = new testUtils.CleanupUtility();
  this.timeout(30000);

  it('Allows me to retrieve default_currency', function() {
    return expect(
      stripe.account.retrieve()
        .then(function(acct) {
          CURRENCY = acct.default_currency;
          return acct;
        })
    ).to.eventually.have.property('default_currency');
  });

  describe('Plan+Subscription flow', function() {
    it('Allows me to: Create a plan and subscribe a customer to it', function() {
      return expect(
        Promise.all([
          stripe.plans.create({
            id: 'plan' + testUtils.getRandomString(),
            amount: 1700,
            currency: CURRENCY,
            interval: 'month',
            nickname: 'Gold Super Amazing Tier',
            product: {
              name: 'product' + testUtils.getRandomString(),
            },
          }),
          stripe.customers.create(CUSTOMER_DETAILS)
        ]).then(function(j) {
          var plan = j[0];
          var customer = j[1];

          cleanup.deleteCustomer(customer.id);
          cleanup.deletePlan(plan.id);

          return stripe.customers.updateSubscription(customer.id, {
            plan: plan.id,
          });
        })
      ).to.eventually.have.property('status', 'active');
    });

    it(
      'Allows me to: Create a plan and subscribe a customer to it, and update subscription (multi-subs API)',
      function() {
        var plan;
        return expect(
          Promise.all([
            stripe.plans.create({
              id: 'plan' + testUtils.getRandomString(),
              amount: 1700,
              currency: CURRENCY,
              interval: 'month',
              nickname: 'Gold Super Amazing Tier',
              product: {
                name: 'product' + testUtils.getRandomString(),
              },
            }),
            stripe.customers.create(CUSTOMER_DETAILS)
          ]).then(function(j) {
            plan = j[0];
            var customer = j[1];

            cleanup.deleteCustomer(customer.id);
            cleanup.deletePlan(plan.id);

            return stripe.customers.createSubscription(customer.id, {
              plan: plan.id,
            });
          }).then(function(subscription) {
            return stripe.customers.updateSubscription(subscription.customer, subscription.id, {
              plan: plan.id, quantity: '3',
            });
          }).then(function(subscription) {
            return [subscription.status, subscription.quantity];
          })
        ).to.eventually.deep.equal(['active', 3]);
      }
    );

    it('Errors when I attempt to subscribe a customer to a non-existent plan', function() {
      return expect(
        stripe.customers.create(CUSTOMER_DETAILS)
          .then(function(customer) {
            cleanup.deleteCustomer(customer.id);

            return stripe.customers.updateSubscription(customer.id, {
              plan: 'someNonExistentPlan' + testUtils.getRandomString(),
            }).then(null, function(err) {
              // Resolve with the error so we can inspect it below
              return err;
            });
          })
      ).to.eventually.satisfy(function(err) {
        return err.type === 'StripeInvalidRequestError' &&
          err.rawType === 'invalid_request_error';
      });
    });

    it('Allows me to: subscribe then cancel with `at_period_end` defined', function() {
      return expect(
        Promise.all([
          stripe.plans.create({
            id: 'plan' + testUtils.getRandomString(),
            amount: 1700,
            currency: CURRENCY,
            interval: 'month',
            nickname: 'Silver Super Amazing Tier',
            product: {
              name: 'product' + testUtils.getRandomString(),
            },
          }),
          stripe.customers.create(CUSTOMER_DETAILS)
        ]).then(function(j) {
          var plan = j[0];
          var customer = j[1];

          cleanup.deleteCustomer(customer.id);
          cleanup.deletePlan(plan.id);

          return stripe.customers.updateSubscription(customer.id, {
            plan: plan.id,
          });
        }).then(function(subscription) {
          return stripe.customers.cancelSubscription(subscription.customer, {
            at_period_end: true,
          });
        })
      ).to.eventually.have.property('cancel_at_period_end', true);
    });

    describe('Plan name variations', function() {
      [
        '34535 355453' + testUtils.getRandomString(),
        'TEST 239291' + testUtils.getRandomString(),
        'TEST_a-i' + testUtils.getRandomString(),
        'foobarbazteston###etwothree' + testUtils.getRandomString(),
      ].forEach(function(planID) {
        it('Allows me to create and retrieve plan with ID: ' + planID, function() {
          return expect(
            stripe.plans.create({
              id: planID,
              amount: 1700,
              currency: CURRENCY,
              interval: 'month',
              nickname: 'generic',
              product: {
                name: 'product' + testUtils.getRandomString(),
              },
            }).then(function() {
              cleanup.deletePlan(planID);
              return stripe.plans.retrieve(planID);
            })
          ).to.eventually.have.property('id', planID);
        });
      });
    });
  });

  describe('Coupon flow', function() {
    var customer;
    var coupon;

    describe('When I create a coupon & customer', function() {
      it('Does so', function() {
        return expect(
          Promise.all([
            stripe.coupons.create({
              percent_off: 20,
              duration: 'once',
            }),
            stripe.customers.create(CUSTOMER_DETAILS)
          ]).then(function(joined) {
            coupon = joined[0];
            customer = joined[1];
          })
        ).to.not.be.eventually.rejected;
      });
      describe('And I apply the coupon to the customer', function() {
        it('Does so', function() {
          return expect(
            stripe.customers.update(customer.id, {
              coupon: coupon.id,
            })
          ).to.not.be.eventually.rejected;
        });
        it('Can be retrieved from that customer', function() {
          return expect(
            stripe.customers.retrieve(customer.id)
          ).to.eventually.have.nested.property('discount.coupon.id', coupon.id);
        });
        describe('The resulting discount', function() {
          it('Can be removed', function() {
            return expect(
              stripe.customers.deleteDiscount(customer.id)
            ).to.eventually.have.property('deleted', true);
          });
          describe('Re-querying it', function() {
            it('Does indeed indicate that it is deleted', function() {
              return expect(
                stripe.customers.retrieve(customer.id)
              ).to.eventually.have.property('discount', null);
            });
          });
        });
      });
    });
  });

  describe('Metadata flow', function() {
    it('Can save and retrieve metadata', function() {
      var customer;
      return expect(
        stripe.customers.create(CUSTOMER_DETAILS)
          .then(function(cust) {
            customer = cust;
            cleanup.deleteCustomer(cust.id);
            return stripe.customers.setMetadata(cust.id, {foo: '123'});
          })
          .then(function() {
            return stripe.customers.getMetadata(customer.id);
          })
      ).to.eventually.deep.equal({foo: '123'});
    });
    it('Can reset metadata', function() {
      var customer;
      return expect(
        stripe.customers.create(CUSTOMER_DETAILS)
          .then(function(cust) {
            customer = cust;
            cleanup.deleteCustomer(cust.id);
            return stripe.customers.setMetadata(cust.id, {baz: '123'});
          })
          .then(function() {
            return stripe.customers.setMetadata(customer.id, null);
          })
          .then(function() {
            return stripe.customers.getMetadata(customer.id);
          })
      ).to.eventually.deep.equal({});
    });
    it('Resets metadata when setting new metadata', function() {
      var customer;
      return expect(
        stripe.customers.create(CUSTOMER_DETAILS)
          .then(function(cust) {
            customer = cust;
            cleanup.deleteCustomer(cust.id);
            return stripe.customers.setMetadata(cust.id, {foo: '123'});
          })
          .then(function() {
            return stripe.customers.setMetadata(customer.id, {baz: '456'});
          })
      ).to.eventually.deep.equal({baz: '456'});
    });
    it('Can set individual key/value pairs', function() {
      var customer;
      return expect(
        stripe.customers.create(CUSTOMER_DETAILS)
          .then(function(cust) {
            customer = cust;
            cleanup.deleteCustomer(cust.id);
          })
          .then(function() {
            return stripe.customers.setMetadata(customer.id, 'baz', 456);
          })
          .then(function() {
            return stripe.customers.setMetadata(customer.id, '_other_', 999);
          })
          .then(function() {
            return stripe.customers.setMetadata(customer.id, 'foo', 123);
          })
          .then(function() {
            // Change foo
            return stripe.customers.setMetadata(customer.id, 'foo', 222);
          })
          .then(function() {
            // Delete baz
            return stripe.customers.setMetadata(customer.id, 'baz', null);
          })
          .then(function() {
            return stripe.customers.getMetadata(customer.id);
          })
      ).to.eventually.deep.equal({_other_: '999', foo: '222'});
    });
    it('Can set individual key/value pairs [with per request token]', function() {
      var customer;
      var authToken = testUtils.getUserStripeKey();
      return expect(
        stripe.customers.create(CUSTOMER_DETAILS)
          .then(function(cust) {
            customer = cust;
            cleanup.deleteCustomer(cust.id);
          })
          .then(function() {
            return stripe.customers.setMetadata(customer.id, {'baz': 456}, authToken);
          })
          .then(function() {
            return stripe.customers.setMetadata(customer.id, '_other_', 999, authToken);
          })
          .then(function() {
            return stripe.customers.setMetadata(customer.id, 'foo', 123, authToken);
          })
          .then(function() {
            // Change foo
            return stripe.customers.setMetadata(customer.id, 'foo', 222, authToken);
          })
          .then(function() {
            // Delete baz
            return stripe.customers.setMetadata(customer.id, 'baz', null, authToken);
          })
          .then(function() {
            return stripe.customers.getMetadata(customer.id, authToken);
          })
      ).to.eventually.deep.equal({_other_: '999', foo: '222'});
    });
  });

  describe('Expanding', function() {
    describe('A customer within a charge', function() {
      it('Allows you to expand a customer object', function() {
        return expect(
          stripe.customers.create(CUSTOMER_DETAILS)
            .then(function(cust) {
              cleanup.deleteCustomer(cust.id);
              return stripe.charges.create({
                customer: cust.id,
                amount: 1700,
                currency: CURRENCY,
                expand: ['customer'],
              });
            })
        ).to.eventually.have.nested.property('customer.created');
      });
    });
    describe('A customer\'s default source', function() {
      it('Allows you to expand a default_source', function() {
        return expect(
          stripe.customers.create({
            description: 'Some customer',
            source: 'tok_visa',
            expand: ['default_source'],
          })
            .then(function(cust) {
              cleanup.deleteCustomer(cust.id);
              return cust;
            })
          // Confirm it's expanded by checking that some prop (e.g. exp_year) exists:
        ).to.eventually.have.nested.property('default_source.exp_year');
      });
    });
  });

  describe('Charge', function() {
    it('Allows you to create a charge', function() {
      return expect(
        stripe.charges.create({
          amount: 1234,
          currency: CURRENCY,
          card: 'tok_chargeDeclined',
          shipping: {
            name: 'Bobby Tables',
            address: {
              line1: '1 Foo St.',
            },
          },
        }).then(null, function(error) {
          return error;
        })
      ).to.eventually.have.nested.property('raw.charge');
    });
  });

  describe('Getting balance', function() {
    it('Allows me to do so', function() {
      return expect(
        stripe.balance.retrieve()
      ).to.eventually.have.property('object', 'balance');
    });
    it('Allows me to do so with specified auth key', function() {
      return expect(
        stripe.balance.retrieve(testUtils.getUserStripeKey())
      ).to.eventually.have.property('object', 'balance');
    });
  });

  describe('Request/Response Events', function() {
    var connectedAccountId;

    before(function(done) {
      // Pick a random connected account to use in the `Stripe-Account` header
      stripe.accounts.list({
        limit: 1,
      }).then(function(accounts) {
        if (accounts.data.length < 1) {
          return done(
            new Error('Test requires at least one Connected Account in the Test Account')
          );
        }

        connectedAccountId = accounts.data[0].id;

        done();
      });
    });

    it('should emit a `request` event to listeners on request', function(done) {
      var apiVersion = '2017-06-05';
      var idempotencyKey = Math.random().toString(36).slice(2);

      function onRequest(request) {
        stripe.off('request', onRequest);

        expect(request).to.eql({
          api_version: 'latest',
          idempotency_key: idempotencyKey,
          method: 'POST',
          path: '/v1/charges',
          account: connectedAccountId,
        });

        done();
      }

      stripe.on('request', onRequest);

      stripe.charges.create({
        amount: 1234,
        currency: 'usd',
        card: 'tok_chargeDeclined',
      }, {
        stripe_version: apiVersion,
        idempotency_key: idempotencyKey,
        stripe_account: connectedAccountId,
      }).then(null, function() {
        // I expect there to be an error here.
      });
    });

    it('should emit a `response` event to listeners on response', function(done) {
      var apiVersion = '2017-06-05';
      var idempotencyKey = Math.random().toString(36).slice(2);

      function onResponse(response) {
        // On the off chance we're picking up a response from a differentrequest
        // then just ignore this and wait for the right one:
        if (response.idempotency_key !== idempotencyKey) {
          return;
        }

        stripe.off('response', onResponse);

        expect(response.api_version).to.equal(apiVersion);
        expect(response.idempotency_key).to.equal(idempotencyKey);
        expect(response.account).to.equal(connectedAccountId);
        expect(response.method).to.equal('POST');
        expect(response.path).to.equal('/v1/charges');
        expect(response.request_id).to.match(/req_[\w\d]/);
        expect(response.status).to.equal(402);
        expect(response.elapsed).to.be.within(50, 30000);

        done();
      }

      stripe.on('response', onResponse);

      stripe.charges.create({
        amount: 1234,
        currency: 'usd',
        card: 'tok_chargeDeclined',
      }, {
        stripe_version: apiVersion,
        idempotency_key: idempotencyKey,
        stripe_account: connectedAccountId,
      }).then(null, function() {
        // I expect there to be an error here.
      });
    });

    it('should not emit a `response` event to removed listeners on response', function(done) {
      function onResponse(response) {
        done(new Error('How did you get here?'));
      }

      stripe.on('response', onResponse);
      stripe.off('response', onResponse);

      stripe.charges.create({
        amount: 1234,
        currency: 'usd',
        card: 'tok_visa',
      }).then(function() {
        done();
      });
    });

    it('Exports errors as types', function() {
      expect(new stripe.errors.StripeInvalidRequestError({
        message: 'error'
      }).type).to.equal('StripeInvalidRequestError');
    });
  });
});
<commit_msg>Use valid characters when creating plans<commit_after>'use strict';

var testUtils = require('./testUtils');
var chai = require('chai');
var stripe = require('../lib/stripe')(
  testUtils.getUserStripeKey(),
  'latest'
);

var expect = chai.expect;

var CUSTOMER_DETAILS = {
  description: 'Some customer',
  card: 'tok_visa',
};

var CURRENCY = '_DEFAULT_CURRENCY_NOT_YET_GOTTEN_';

describe('Flows', function() {
  // Note: These tests must be run as one so we can retrieve the
  // default_currency (required in subsequent tests);

  var cleanup = new testUtils.CleanupUtility();
  this.timeout(30000);

  it('Allows me to retrieve default_currency', function() {
    return expect(
      stripe.account.retrieve()
        .then(function(acct) {
          CURRENCY = acct.default_currency;
          return acct;
        })
    ).to.eventually.have.property('default_currency');
  });

  describe('Plan+Subscription flow', function() {
    it('Allows me to: Create a plan and subscribe a customer to it', function() {
      return expect(
        Promise.all([
          stripe.plans.create({
            id: 'plan' + testUtils.getRandomString(),
            amount: 1700,
            currency: CURRENCY,
            interval: 'month',
            nickname: 'Gold Super Amazing Tier',
            product: {
              name: 'product' + testUtils.getRandomString(),
            },
          }),
          stripe.customers.create(CUSTOMER_DETAILS)
        ]).then(function(j) {
          var plan = j[0];
          var customer = j[1];

          cleanup.deleteCustomer(customer.id);
          cleanup.deletePlan(plan.id);

          return stripe.customers.updateSubscription(customer.id, {
            plan: plan.id,
          });
        })
      ).to.eventually.have.property('status', 'active');
    });

    it(
      'Allows me to: Create a plan and subscribe a customer to it, and update subscription (multi-subs API)',
      function() {
        var plan;
        return expect(
          Promise.all([
            stripe.plans.create({
              id: 'plan' + testUtils.getRandomString(),
              amount: 1700,
              currency: CURRENCY,
              interval: 'month',
              nickname: 'Gold Super Amazing Tier',
              product: {
                name: 'product' + testUtils.getRandomString(),
              },
            }),
            stripe.customers.create(CUSTOMER_DETAILS)
          ]).then(function(j) {
            plan = j[0];
            var customer = j[1];

            cleanup.deleteCustomer(customer.id);
            cleanup.deletePlan(plan.id);

            return stripe.customers.createSubscription(customer.id, {
              plan: plan.id,
            });
          }).then(function(subscription) {
            return stripe.customers.updateSubscription(subscription.customer, subscription.id, {
              plan: plan.id, quantity: '3',
            });
          }).then(function(subscription) {
            return [subscription.status, subscription.quantity];
          })
        ).to.eventually.deep.equal(['active', 3]);
      }
    );

    it('Errors when I attempt to subscribe a customer to a non-existent plan', function() {
      return expect(
        stripe.customers.create(CUSTOMER_DETAILS)
          .then(function(customer) {
            cleanup.deleteCustomer(customer.id);

            return stripe.customers.updateSubscription(customer.id, {
              plan: 'someNonExistentPlan' + testUtils.getRandomString(),
            }).then(null, function(err) {
              // Resolve with the error so we can inspect it below
              return err;
            });
          })
      ).to.eventually.satisfy(function(err) {
        return err.type === 'StripeInvalidRequestError' &&
          err.rawType === 'invalid_request_error';
      });
    });

    it('Allows me to: subscribe then cancel with `at_period_end` defined', function() {
      return expect(
        Promise.all([
          stripe.plans.create({
            id: 'plan' + testUtils.getRandomString(),
            amount: 1700,
            currency: CURRENCY,
            interval: 'month',
            nickname: 'Silver Super Amazing Tier',
            product: {
              name: 'product' + testUtils.getRandomString(),
            },
          }),
          stripe.customers.create(CUSTOMER_DETAILS)
        ]).then(function(j) {
          var plan = j[0];
          var customer = j[1];

          cleanup.deleteCustomer(customer.id);
          cleanup.deletePlan(plan.id);

          return stripe.customers.updateSubscription(customer.id, {
            plan: plan.id,
          });
        }).then(function(subscription) {
          return stripe.customers.cancelSubscription(subscription.customer, {
            at_period_end: true,
          });
        })
      ).to.eventually.have.property('cancel_at_period_end', true);
    });

    describe('Plan name variations', function() {
      [
        '34535_355453' + testUtils.getRandomString(),
        'TEST_239291' + testUtils.getRandomString(),
        'TEST_a-i' + testUtils.getRandomString(),
        'foobarbazteston___etwothree' + testUtils.getRandomString(),
      ].forEach(function(planID) {
        it('Allows me to create and retrieve plan with ID: ' + planID, function() {
          return expect(
            stripe.plans.create({
              id: planID,
              amount: 1700,
              currency: CURRENCY,
              interval: 'month',
              nickname: 'generic',
              product: {
                name: 'product' + testUtils.getRandomString(),
              },
            }).then(function() {
              cleanup.deletePlan(planID);
              return stripe.plans.retrieve(planID);
            })
          ).to.eventually.have.property('id', planID);
        });
      });
    });
  });

  describe('Coupon flow', function() {
    var customer;
    var coupon;

    describe('When I create a coupon & customer', function() {
      it('Does so', function() {
        return expect(
          Promise.all([
            stripe.coupons.create({
              percent_off: 20,
              duration: 'once',
            }),
            stripe.customers.create(CUSTOMER_DETAILS)
          ]).then(function(joined) {
            coupon = joined[0];
            customer = joined[1];
          })
        ).to.not.be.eventually.rejected;
      });
      describe('And I apply the coupon to the customer', function() {
        it('Does so', function() {
          return expect(
            stripe.customers.update(customer.id, {
              coupon: coupon.id,
            })
          ).to.not.be.eventually.rejected;
        });
        it('Can be retrieved from that customer', function() {
          return expect(
            stripe.customers.retrieve(customer.id)
          ).to.eventually.have.nested.property('discount.coupon.id', coupon.id);
        });
        describe('The resulting discount', function() {
          it('Can be removed', function() {
            return expect(
              stripe.customers.deleteDiscount(customer.id)
            ).to.eventually.have.property('deleted', true);
          });
          describe('Re-querying it', function() {
            it('Does indeed indicate that it is deleted', function() {
              return expect(
                stripe.customers.retrieve(customer.id)
              ).to.eventually.have.property('discount', null);
            });
          });
        });
      });
    });
  });

  describe('Metadata flow', function() {
    it('Can save and retrieve metadata', function() {
      var customer;
      return expect(
        stripe.customers.create(CUSTOMER_DETAILS)
          .then(function(cust) {
            customer = cust;
            cleanup.deleteCustomer(cust.id);
            return stripe.customers.setMetadata(cust.id, {foo: '123'});
          })
          .then(function() {
            return stripe.customers.getMetadata(customer.id);
          })
      ).to.eventually.deep.equal({foo: '123'});
    });
    it('Can reset metadata', function() {
      var customer;
      return expect(
        stripe.customers.create(CUSTOMER_DETAILS)
          .then(function(cust) {
            customer = cust;
            cleanup.deleteCustomer(cust.id);
            return stripe.customers.setMetadata(cust.id, {baz: '123'});
          })
          .then(function() {
            return stripe.customers.setMetadata(customer.id, null);
          })
          .then(function() {
            return stripe.customers.getMetadata(customer.id);
          })
      ).to.eventually.deep.equal({});
    });
    it('Resets metadata when setting new metadata', function() {
      var customer;
      return expect(
        stripe.customers.create(CUSTOMER_DETAILS)
          .then(function(cust) {
            customer = cust;
            cleanup.deleteCustomer(cust.id);
            return stripe.customers.setMetadata(cust.id, {foo: '123'});
          })
          .then(function() {
            return stripe.customers.setMetadata(customer.id, {baz: '456'});
          })
      ).to.eventually.deep.equal({baz: '456'});
    });
    it('Can set individual key/value pairs', function() {
      var customer;
      return expect(
        stripe.customers.create(CUSTOMER_DETAILS)
          .then(function(cust) {
            customer = cust;
            cleanup.deleteCustomer(cust.id);
          })
          .then(function() {
            return stripe.customers.setMetadata(customer.id, 'baz', 456);
          })
          .then(function() {
            return stripe.customers.setMetadata(customer.id, '_other_', 999);
          })
          .then(function() {
            return stripe.customers.setMetadata(customer.id, 'foo', 123);
          })
          .then(function() {
            // Change foo
            return stripe.customers.setMetadata(customer.id, 'foo', 222);
          })
          .then(function() {
            // Delete baz
            return stripe.customers.setMetadata(customer.id, 'baz', null);
          })
          .then(function() {
            return stripe.customers.getMetadata(customer.id);
          })
      ).to.eventually.deep.equal({_other_: '999', foo: '222'});
    });
    it('Can set individual key/value pairs [with per request token]', function() {
      var customer;
      var authToken = testUtils.getUserStripeKey();
      return expect(
        stripe.customers.create(CUSTOMER_DETAILS)
          .then(function(cust) {
            customer = cust;
            cleanup.deleteCustomer(cust.id);
          })
          .then(function() {
            return stripe.customers.setMetadata(customer.id, {'baz': 456}, authToken);
          })
          .then(function() {
            return stripe.customers.setMetadata(customer.id, '_other_', 999, authToken);
          })
          .then(function() {
            return stripe.customers.setMetadata(customer.id, 'foo', 123, authToken);
          })
          .then(function() {
            // Change foo
            return stripe.customers.setMetadata(customer.id, 'foo', 222, authToken);
          })
          .then(function() {
            // Delete baz
            return stripe.customers.setMetadata(customer.id, 'baz', null, authToken);
          })
          .then(function() {
            return stripe.customers.getMetadata(customer.id, authToken);
          })
      ).to.eventually.deep.equal({_other_: '999', foo: '222'});
    });
  });

  describe('Expanding', function() {
    describe('A customer within a charge', function() {
      it('Allows you to expand a customer object', function() {
        return expect(
          stripe.customers.create(CUSTOMER_DETAILS)
            .then(function(cust) {
              cleanup.deleteCustomer(cust.id);
              return stripe.charges.create({
                customer: cust.id,
                amount: 1700,
                currency: CURRENCY,
                expand: ['customer'],
              });
            })
        ).to.eventually.have.nested.property('customer.created');
      });
    });
    describe('A customer\'s default source', function() {
      it('Allows you to expand a default_source', function() {
        return expect(
          stripe.customers.create({
            description: 'Some customer',
            source: 'tok_visa',
            expand: ['default_source'],
          })
            .then(function(cust) {
              cleanup.deleteCustomer(cust.id);
              return cust;
            })
          // Confirm it's expanded by checking that some prop (e.g. exp_year) exists:
        ).to.eventually.have.nested.property('default_source.exp_year');
      });
    });
  });

  describe('Charge', function() {
    it('Allows you to create a charge', function() {
      return expect(
        stripe.charges.create({
          amount: 1234,
          currency: CURRENCY,
          card: 'tok_chargeDeclined',
          shipping: {
            name: 'Bobby Tables',
            address: {
              line1: '1 Foo St.',
            },
          },
        }).then(null, function(error) {
          return error;
        })
      ).to.eventually.have.nested.property('raw.charge');
    });
  });

  describe('Getting balance', function() {
    it('Allows me to do so', function() {
      return expect(
        stripe.balance.retrieve()
      ).to.eventually.have.property('object', 'balance');
    });
    it('Allows me to do so with specified auth key', function() {
      return expect(
        stripe.balance.retrieve(testUtils.getUserStripeKey())
      ).to.eventually.have.property('object', 'balance');
    });
  });

  describe('Request/Response Events', function() {
    var connectedAccountId;

    before(function(done) {
      // Pick a random connected account to use in the `Stripe-Account` header
      stripe.accounts.list({
        limit: 1,
      }).then(function(accounts) {
        if (accounts.data.length < 1) {
          return done(
            new Error('Test requires at least one Connected Account in the Test Account')
          );
        }

        connectedAccountId = accounts.data[0].id;

        done();
      });
    });

    it('should emit a `request` event to listeners on request', function(done) {
      var apiVersion = '2017-06-05';
      var idempotencyKey = Math.random().toString(36).slice(2);

      function onRequest(request) {
        stripe.off('request', onRequest);

        expect(request).to.eql({
          api_version: 'latest',
          idempotency_key: idempotencyKey,
          method: 'POST',
          path: '/v1/charges',
          account: connectedAccountId,
        });

        done();
      }

      stripe.on('request', onRequest);

      stripe.charges.create({
        amount: 1234,
        currency: 'usd',
        card: 'tok_chargeDeclined',
      }, {
        stripe_version: apiVersion,
        idempotency_key: idempotencyKey,
        stripe_account: connectedAccountId,
      }).then(null, function() {
        // I expect there to be an error here.
      });
    });

    it('should emit a `response` event to listeners on response', function(done) {
      var apiVersion = '2017-06-05';
      var idempotencyKey = Math.random().toString(36).slice(2);

      function onResponse(response) {
        // On the off chance we're picking up a response from a differentrequest
        // then just ignore this and wait for the right one:
        if (response.idempotency_key !== idempotencyKey) {
          return;
        }

        stripe.off('response', onResponse);

        expect(response.api_version).to.equal(apiVersion);
        expect(response.idempotency_key).to.equal(idempotencyKey);
        expect(response.account).to.equal(connectedAccountId);
        expect(response.method).to.equal('POST');
        expect(response.path).to.equal('/v1/charges');
        expect(response.request_id).to.match(/req_[\w\d]/);
        expect(response.status).to.equal(402);
        expect(response.elapsed).to.be.within(50, 30000);

        done();
      }

      stripe.on('response', onResponse);

      stripe.charges.create({
        amount: 1234,
        currency: 'usd',
        card: 'tok_chargeDeclined',
      }, {
        stripe_version: apiVersion,
        idempotency_key: idempotencyKey,
        stripe_account: connectedAccountId,
      }).then(null, function() {
        // I expect there to be an error here.
      });
    });

    it('should not emit a `response` event to removed listeners on response', function(done) {
      function onResponse(response) {
        done(new Error('How did you get here?'));
      }

      stripe.on('response', onResponse);
      stripe.off('response', onResponse);

      stripe.charges.create({
        amount: 1234,
        currency: 'usd',
        card: 'tok_visa',
      }).then(function() {
        done();
      });
    });

    it('Exports errors as types', function() {
      expect(new stripe.errors.StripeInvalidRequestError({
        message: 'error'
      }).type).to.equal('StripeInvalidRequestError');
    });
  });
});
<|endoftext|>


<commit_before>describe('binary-variations', function() {

    it('should compute all possible binary permutations', function() {
        var variations = ['a', 'b', 'c'];
        var permutations = binaryVariations(variations);

        expect(permutations.length).toBe(Math.pow(2, variations.length) - 1);

        variations = ['a', 'b', 'c', 'd'];
        permutations = binaryVariations(variations);

        expect(permutations.length).toBe(Math.pow(2, variations.length) - 1);

        variations = ['a', 'b', 'c', 'd', 'e'];
        permutations = binaryVariations(variations);

        expect(permutations.length).toBe(Math.pow(2, variations.length) - 1);
    });

    describe('filter', function() {

        it('should include single items', function () {
            var variations = ['a', 'b', 'c'];
            var filter = {
                include: ['b']
            };
            var permutations = binaryVariations(variations, filter);

            expect(permutations.length).toBe(1);
            expect(permutations[0]).toBe('b');

            filter = {
                include: ['b', 'c']
            };
            permutations = binaryVariations(variations, filter);

            expect(permutations.length).toBe(2);
            expect(permutations.indexOf('b')).toBeGreaterThan(-1);
            expect(permutations.indexOf('c')).toBeGreaterThan(-1);
        });

        it('should include containing combinations', function () {
            var variations = ['a', 'b', 'c', 'd'];
            var filter = {
                include: [['b', 'd']]
            };
            var permutations = binaryVariations(variations, filter);

            expect(permutations.length).toBeGreaterThan(Math.pow(2, 2) - 1);

            for (var i = 0; i < permutations.length; i++) {
                var permutation = permutations[0];

                expect(permutation.indexOf('b')).toBeGreaterThan(-1);
                expect(permutation.indexOf('d')).toBeGreaterThan(-1);
            }
        });

        it('should exclude single items', function () {
            var variations = ['a', 'b', 'c'];
            var filter = {
                exclude: ['b']
            };
            var permutations = binaryVariations(variations, filter);
            var permutationsLength = Math.pow(2, variations.length) - 1;

            expect(permutations.length).toBe(permutationsLength - 1);

            for (var i = 0; i < permutations.length; i++) {
                var permutation = permutations[0];

                if (permutation.length === 1) {
                    expect(permutations[0]).not.toBe('b');
                }
            }

            filter = {
                exclude: ['b', 'c']
            };
            permutations = binaryVariations(variations, filter);

            expect(permutations.length).toBe(permutationsLength - 2);

            for (var i = 0; i < permutations.length; i++) {
                var permutation = permutations[0];

                if (permutation.length === 1) {
                    expect(permutations[0]).not.toBe('b');
                    expect(permutations[0]).not.toBe('c');
                }
            }
        });
    });

    describe('.expect()', function() {

        it('should return the amount of all ordered, binary permutations [(2^n) - 1]', function() {
            var variations = ['a', 'b', 'c'];

            expect(binaryVariations.expect(variations)).toBe(Math.pow(2, variations.length) - 1);
        });
    });

    describe('.join()', function() {

        var variations = ['a', 'b', 'c'];

        it('should join by default sparator', function() {
            expect(binaryVariations.join(variations)).toBe(variations.join());
        });

        it('should join by given sparator', function() {
            expect(binaryVariations.join(variations, '-')).toBe(variations.join('-'));
        });

        it('should join and add prefix', function() {
            expect(binaryVariations.join(variations, ',', '-')).toBe('-' + variations.join(','));
        });

        it('should join and add suffix', function() {
            expect(binaryVariations.join(variations, ',', '', '-')).toBe(variations.join(',') + '-');
        });

        it('should join and add prefix + suffix', function() {
            expect(binaryVariations.join(variations, ',', '-', '-')).toBe('-' + variations.join(',') + '-');
        });
    });
});<commit_msg>added more tests - test covarage 100%<commit_after>describe('binary-variations', function() {

    it('should compute all possible binary permutations', function() {
        var variations = ['a', 'b', 'c'];
        var permutations = binaryVariations(variations);

        expect(permutations.length).toBe(Math.pow(2, variations.length) - 1);

        variations = ['a', 'b', 'c', 'd'];
        permutations = binaryVariations(variations);

        expect(permutations.length).toBe(Math.pow(2, variations.length) - 1);

        variations = ['a', 'b', 'c', 'd', 'e'];
        permutations = binaryVariations(variations);

        expect(permutations.length).toBe(Math.pow(2, variations.length) - 1);
    });

    describe('filter', function() {

        describe('include', function() {
            it('should include single items', function () {
                var variations = ['a', 'b', 'c'];
                var filter = {
                    include: ['b']
                };
                var permutations = binaryVariations(variations, filter);

                expect(permutations.length).toBe(1);
                expect(permutations[0][0]).toBe('b');

                filter = {
                    include: ['b', 'c']
                };
                permutations = binaryVariations(variations, filter);

                expect(permutations.length).toBe(2);

                expect(permutations[0].join()).toMatch(/^[bc]$/);
                expect(permutations[1].join()).toMatch(/^[bc]$/);
            });

            it('should include containing combinations', function () {
                var variations = ['a', 'b', 'c', 'd'];
                var filter = {
                    include: [['b', 'd']]
                };
                var permutations = binaryVariations(variations, filter);

                expect(permutations.length).toBeGreaterThan(Math.pow(2, 2) - 1);

                for (var i = 0; i < permutations.length; i++) {
                    var permutation = permutations[0];

                    expect(permutation.indexOf('b')).toBeGreaterThan(-1);
                    expect(permutation.indexOf('d')).toBeGreaterThan(-1);
                }
            });
        });

        describe('exclude', function() {
            it('should exclude single items', function () {
                var variations = ['a', 'b', 'c'];
                var filter = {
                    exclude: ['b']
                };
                var permutations = binaryVariations(variations, filter);
                var permutationsLength = Math.pow(2, variations.length) - 1;

                expect(permutations.length).toBe(permutationsLength - 1);

                for (var i = 0; i < permutations.length; i++) {
                    var permutation = permutations[i];

                    if (permutation.length === 1) {
                        expect(permutations[0]).not.toBe('b');
                    }
                }

                filter = {
                    exclude: ['b', 'c']
                };
                permutations = binaryVariations(variations, filter);

                expect(permutations.length).toBe(permutationsLength - 2);

                for (var i = 0; i < permutations.length; i++) {
                    var permutation = permutations[0];

                    if (permutation.length === 1) {
                        expect(permutations[0]).not.toBe('b');
                        expect(permutations[0]).not.toBe('c');
                    }
                }
            });

            it('should exclude containing combinations', function () {
                var variations = ['a', 'b', 'c', 'd'];
                var filter = {
                    exclude: [['b', 'd']]
                };
                var permutations = binaryVariations(variations, filter);
                var permutationsLength = Math.pow(2, variations.length) - 1;

                expect(permutations.length).toBeLessThan(permutationsLength - (Math.pow(2, 2) - 1));

                for (var i = 0; i < permutations.length; i++) {
                    var permutation = permutations[0];

                    if (permutation.length > 1) {
                        expect(permutation.indexOf('b')).toBe(-1);
                        expect(permutation.indexOf('d')).toBe(-1);
                    }
                }
            });
        });

        describe('precedence', function() {
            it('should give precedence to include by default', function() {
                var variations = ['a', 'b', 'c'];
                var filter = {
                    include: ['b'],
                    exclude: ['b']
                };
                var permutations = binaryVariations(variations, filter);

                expect(permutations.length).toBe(1);
                expect(permutations[0][0]).toBe('b');
            });

            it('should give precedence to include if `precedence=true`', function() {
                var variations = ['a', 'b', 'c'];
                var filter = {
                    include: ['b'],
                    exclude: ['b'],
                    precedence: true
                };
                var permutations = binaryVariations(variations, filter);

                expect(permutations.length).toBe(1);
                expect(permutations[0][0]).toBe('b');
            });

            it('should give precedence to exclude if `precedence=false`', function() {
                var variations = ['a', 'b', 'c'];
                var filter = {
                    include: ['b'],
                    exclude: ['b'],
                    precedence: false
                };
                var permutations = binaryVariations(variations, filter);
                var permutationsLength = Math.pow(2, variations.length) - 1;

                expect(permutations.length).toBe(permutationsLength - 1);

                for (var i = 0; i < permutations.length; i++) {
                    var permutation = permutations[i];

                    if (permutation.length === 1) {
                        expect(permutations[0]).not.toBe('b');
                    }
                }
            });
        });
    });

    describe('.expect()', function() {

        it('should return the amount of all ordered, binary permutations [(2^n) - 1]', function() {
            var variations = ['a', 'b', 'c'];

            expect(binaryVariations.expect(variations)).toBe(Math.pow(2, variations.length) - 1);
        });
    });

    describe('.join()', function() {

        var variations = ['a', 'b', 'c'];

        it('should join by default sparator', function() {
            expect(binaryVariations.join(variations)).toBe(variations.join());
        });

        it('should join by given sparator', function() {
            expect(binaryVariations.join(variations, '-')).toBe(variations.join('-'));
        });

        it('should join and add prefix', function() {
            expect(binaryVariations.join(variations, ',', '-')).toBe('-' + variations.join(','));
        });

        it('should join and add suffix', function() {
            expect(binaryVariations.join(variations, ',', '', '-')).toBe(variations.join(',') + '-');
        });

        it('should join and add prefix + suffix', function() {
            expect(binaryVariations.join(variations, ',', '-', '-')).toBe('-' + variations.join(',') + '-');
        });
    });
});<|endoftext|>