text: var EventEmitter = require('events').EventEmitter
    , Timer = require('components/timer')
    ;
  
  describe('Timer', function () {
    var events
      , element
      , timer
      ;
  
    beforeEach(function () {
      events = new EventEmitter();
      element = document.createElement('div');
    });
  
    describe('start event', function () {
      it('should respond to a \'start\' event', function () {
        timer = new Timer(events, element);
  
        events.emit('start');
  
        timer.state.should.equal(timer.RUNNING);
      });
  
      it('should respond to a \'start\' event unless \'startOnChange\' option is \'false\'', function () {
        timer = new Timer(events, element, { startOnChange: false });
  
        events.emit('start');
  
        timer.state.should.equal(timer.INITIAL);
      });
    });
  
    describe('timer events', function () {
      beforeEach(function () {
        timer = new Timer(events, element);
      });
  
      it('should be in an initial state', function () {
        timer.state.should.equal(timer.INITIAL);
      });
  
      it('should respond to a startTimer event', function () {
        events.emit('startTimer');
  
        timer.state.should.equal(timer.RUNNING);
      });
  
      it('should respond to a pauseTimer event', function () {
        events.emit('pauseTimer');
  
        timer.state.should.equal(timer.PAUSED);
      });
  
      it('should respond to a toggleTimer event', function () {
        events.emit('toggleTimer');
  
        timer.state.should.equal(timer.RUNNING);
  
        events.emit('toggleTimer');
  
        timer.state.should.equal(timer.PAUSED);
  
        events.emit('toggleTimer');
  
        timer.state.should.equal(timer.RUNNING);
      });
  
      it('should respond to a resetTimer event', function () {
        events.emit('resetTimer');
  
        timer.state.should.equal(timer.INITIAL);
      });
  
      it('should respond to a resetTimer event unless \'resetable\' option is set to \'false\'', function () {
        timer = new Timer(events, element, { resetable: false });
  
        events.emit('startTimer');
        events.emit('resetTimer');
  
        timer.state.should.equal(timer.RUNNING);
      });
  
      describe('sequence of events', function () {
        it('should be in a correct state after startTimer, pauseTimer', function () {
          ['startTimer', 'pauseTimer'].forEach(function (event) {
            events.emit(event);
          });
  
          timer.state.should.equal(timer.PAUSED);
        });
  
        it('should be in a correct state after startTimer, resetTimer', function () {
          ['startTimer', 'resetTimer'].forEach(function (event) {
            events.emit(event);
          });
  
          timer.state.should.equal(timer.INITIAL);
        });
  
        it('should be in a correct state after startTimer, pauseTimer, startTimer', function () {
          ['startTimer', 'pauseTimer', 'startTimer'].forEach(function (event) {
            events.emit(event);
          });
  
          timer.state.should.equal(timer.RUNNING);
        });
  
        it('should be in a correct state after startTimer, pauseTimer, resetTimer', function () {
          ['startTimer', 'pauseTimer', 'resetTimer'].forEach(function (event) {
            events.emit(event);
          });
  
          timer.state.should.equal(timer.INITIAL);
        });
      });
    });
  
    describe('tick', function () {
      beforeEach(function () {
        timer = new Timer(events, element);
      });
  
      it('timer in INITIAL state does not progresses the elapsed time', function (done) {
        setTimeout(function () {
          timer.tick();
  
          timer.chronos.elapsedTime.should.equal(0);
          done();
        })
      });
  
      it('timer in RUNNING state progresses the elapsed time', function (done) {
        events.emit('startTimer');
  
        setTimeout(function () {
          timer.tick();
  
          timer.chronos.elapsedTime.should.be.above(0);
          done();
        })
      });
  
      it('timer in PAUSED state does not progresses the elapsed time', function (done) {
        events.emit('pauseTimer');
  
        setTimeout(function () {
          timer.tick();
  
          timer.chronos.elapsedTime.should.equal(0);
          done();
        })
      });
    });
  
    describe('view', function () {
      var millis = 1,
        seconds = 1000 * millis,
        minutes = 60 * seconds,
        hours = 60 * minutes;
  
      it('defaults to H:mm:ss', function () {
        timer = new Timer(events, element);
        timer.chronos.elapsedTime = 1 * hours + 23 * minutes + 45 * seconds + 678 * millis;
  
        timer.tick();
  
        element.innerHTML.should.equal('1:23:45');
      })
  
      it('defaults view can be overriden', function () {
        timer = new Timer(events, element, {
          formatter: function (elapsedTime) {
            var left = elapsedTime;
            var millis = left % 1000; left = Math.floor(left / 1000);
            var seconds = left % 60; left = Math.floor(left / 60);
            var minutes = left;
  
            return [minutes, seconds]
              .map(function (d) { return '' + d; })
              .map(function (s) { return padStart(s, 2, '0'); })
              .join(':');
          }
        });
        timer.chronos.elapsedTime = 1 * hours + 23 * minutes + 45 * seconds + 678 * millis;
  
        timer.tick();
  
        element.innerHTML.should.equal('83:45');
      })
  
      it('can be disabled', function () {
        timer = new Timer(events, element, {
          enabled: false
        });
        timer.chronos.elapsedTime = 1 * hours + 23 * minutes + 45 * seconds + 678 * millis;
  
        timer.tick();
  
        element.innerHTML.should.equal('');
      })
    });
  });
  
  function padStart(s, length, pad) {
    var result = s;
    while (result.length < length) {
      result = pad + result;
    }
    return result;
  }