describe("Keyboard Support Tests", function() {

  var testSlider,

      handle1,

      handle2,

      keyboardEvent,

      initialMinVal = 0,

      initialMaxVal = 10,

      initialStepVal = 1,

      initialSliderVal = 5;



  /*

    Before/After setup

  */

  beforeEach(function() {

    // Create keyboard event

    keyboardEvent = document.createEvent("Events");

    keyboardEvent.initEvent("keydown", true, true);

  });



  afterEach(function() {

    if(testSlider) { testSlider.slider('destroy'); }

    keyboardEvent = null;

    keyboardEvent = null;

  });



  /*

    Begin Tests

  */

  describe("Clicking on slider handle automatically gives it focus", function() {



    beforeEach(function() {

      testSlider = $("#testSlider1").slider({

        id: 'testSlider'

      });

      handle1 = $("#testSlider").find(".slider-handle:first");

    });



    it("clicking on handle1 gives focus to handle1", function(done) {

      handle1.focus(function() {

        expect(true).toBeTruthy();

        done();

      });

      handle1.focus();

    });

  });



  describe("When slider handle has TAB focus", function() {



    it("should display it's tooltip if 'tooltip' option is set to 'show'", function() {

      testSlider = $("#testSlider1").slider({

        id: 'testSlider',

        tooltip: 'show'

      });

      handle1 = $("#testSlider").find(".slider-handle:first");



      // Check for no tooltip before focus

      var tooltipIsShown = $("#testSlider").find("div.tooltip").hasClass("in");

      expect(tooltipIsShown).toBeFalsy();



      handle1.focus();



      // Tooltip should be present after focus

      tooltipIsShown = $("#testSlider").find("div.tooltip").hasClass("in");

      expect(tooltipIsShown).toBeTruthy();

    });



    it("should not display it's tooltip if 'tooltip' option is set to 'hide'", function() {

      testSlider = $("#testSlider1").slider({

        id: 'testSlider',

        tooltip: 'hide'

      });

      handle1 = $("#testSlider").find(".slider-handle:first");



      // Check for hidden tooltip before focus

      var tooltipIsHidden = $("#testSlider").children("div.tooltip").hasClass("hide");

      expect(tooltipIsHidden).toBeTruthy();



      handle1.focus();



      // Tooltip should remain hidden after focus

      tooltipIsHidden = $("#testSlider").children("div.tooltip").hasClass("hide");

      expect(tooltipIsHidden).toBeTruthy();

    });



    it("should not affect the tooltip display if 'tooltip' option is set to 'always'", function() {

      testSlider = $("#testSlider1").slider({

        id: 'testSlider',

        tooltip: 'always'

      });

      handle1 = $("#testSlider").find(".slider-handle:first");

      var $tooltip = $("#testSlider").children("div.tooltip");



      // Check for shown tooltip before focus

      var tooltipIsShown = $tooltip.hasClass("in");

      expect(tooltipIsShown).toBeTruthy();



      handle1.focus();



      // Tooltip should remain present after focus

      tooltipIsShown = $tooltip.hasClass("in");

      expect(tooltipIsShown).toBeTruthy();

    });

  });



  describe("For horizontal sliders where its handle has focus", function() {



    beforeEach(function() {

      // Initialize the slider

      testSlider = $("#testSlider1").slider({

        id: 'testSlider',

        orientation: 'horizontal',

        min: initialMinVal,

        max: initialMaxVal,

        step: initialStepVal,

        value: initialSliderVal

      });

      // Focus on handle1

      handle1 = $("#testSlider .min-slider-handle");

      handle1.focus();

    });



    it("moves to the left by the 'step' value when the LEFT arrow key is pressed", function(done) {

      handle1.on("keydown", function() {

        var sliderValue = $("#testSlider1").slider('getValue');

        var expectedSliderValue = initialSliderVal - initialStepVal;



        expect(sliderValue).toBe(expectedSliderValue);



        done();

      });



      keyboardEvent.keyCode = keyboardEvent.which = 37;

      handle1[0].dispatchEvent(keyboardEvent);

    });



    it("moves to the right by the 'step' value when the RIGHT arrow key is pressed", function(done) {

      handle1.on("keydown", function() {

        var sliderValue = $("#testSlider1").slider('getValue');

        var expectedSliderValue = initialSliderVal + initialStepVal;



        expect(sliderValue).toBe(expectedSliderValue);



        done();

      });



      keyboardEvent.keyCode = keyboardEvent.which = 39;

      handle1[0].dispatchEvent(keyboardEvent);

    });



    it("moves to the left by the 'step' value when the DOWN arrow key is pressed", function(done) {

      handle1.on("keydown", function() {

        var sliderValue = testSlider.slider('getValue');

        var expectedSliderValue = initialSliderVal - initialStepVal;



        expect(sliderValue).toBe(expectedSliderValue);



        done();

      });



      keyboardEvent.keyCode = keyboardEvent.which = 40;

      handle1[0].dispatchEvent(keyboardEvent);

    });



    it("moves to the right by the 'step' value when the UP arrow key is pressed", function(done) {

      handle1.on("keydown", function() {

        var sliderValue = testSlider.slider('getValue');

        var expectedSliderValue = initialSliderVal + initialStepVal;



        expect(sliderValue).toBe(expectedSliderValue);



        done();

      });



      keyboardEvent.keyCode = keyboardEvent.which = 38;

      handle1[0].dispatchEvent(keyboardEvent);

    });

  });



  describe("For vertical sliders where its handle has focus", function() {



    beforeEach(function() {

      // Initialize the slider

      testSlider = $("#testSlider1").slider({

        id: 'testSlider',

        orientation: 'vertical',

        min: initialMinVal,

        max: initialMaxVal,

        step: initialStepVal,

        value: initialSliderVal

      });

      // Focus on handle1

      handle1 = $("#testSlider").find(".slider-handle:first");

      handle1.focus();

    });



    it("moves down by the 'step' value when the LEFT arrow key is pressed", function(done) {

      handle1.on("keydown", function() {

        var sliderValue = testSlider.slider('getValue');

        var expectedSliderValue = initialSliderVal - initialStepVal;



        expect(sliderValue).toBe(expectedSliderValue);



        done();

      });



      keyboardEvent.keyCode = keyboardEvent.which = 37;

      handle1[0].dispatchEvent(keyboardEvent);

    });



    it("moves up by the 'step' value when the RIGHT arrow key is pressed", function(done) {

      handle1.on("keydown", function() {

        var sliderValue = testSlider.slider('getValue');

        var expectedSliderValue = initialSliderVal + initialStepVal;



        expect(sliderValue).toBe(expectedSliderValue);



        done();

      });



      keyboardEvent.keyCode = keyboardEvent.which = 39;

      handle1[0].dispatchEvent(keyboardEvent);

    });



    it("moves down by the 'step' value when the DOWN arrow key is pressed", function(done) {

      handle1.on("keydown", function() {

        var sliderValue = testSlider.slider('getValue');

        var expectedSliderValue = initialSliderVal - initialStepVal;



        expect(sliderValue).toBe(expectedSliderValue);



        done();

      });



      keyboardEvent.keyCode = keyboardEvent.which = 40;

      handle1[0].dispatchEvent(keyboardEvent);

    });



    it("moves up by the 'step' value when the UP arrow key is pressed", function(done) {

      handle1.on("keydown", function() {

        var sliderValue = testSlider.slider('getValue');

        var expectedSliderValue = initialSliderVal + initialStepVal;



        expect(sliderValue).toBe(expectedSliderValue);



        done();

      });



      keyboardEvent.keyCode = keyboardEvent.which = 38;

      handle1[0].dispatchEvent(keyboardEvent);

    });

  });



  describe("For a reversed slider (regardless of 'orientation')", function() {



    beforeEach(function() {

      // Initialize the slider

      testSlider = $("#testSlider1").slider({

        id: 'testSlider',

        reversed: true,

        min: initialMinVal,

        max: initialMaxVal,

        step: initialStepVal,

        value: initialSliderVal

      });

      // Focus on handle1

      handle1 = $("#testSlider").find(".slider-handle:first");

      handle1.focus();

    });



    it("moves to the left by the 'step' value when the LEFT arrow key is pressed", function(done) {

      handle1.on("keydown", function() {

        var sliderValue = testSlider.slider('getValue');

        var expectedSliderValue = initialSliderVal - initialStepVal;



        expect(sliderValue).toBe(expectedSliderValue);



        done();

      });



      keyboardEvent.keyCode = keyboardEvent.which = 37;

      handle1[0].dispatchEvent(keyboardEvent);

    });



    it("moves to the right by the 'step' value when the RIGHT arrow key is pressed", function(done) {

      handle1.on("keydown", function() {

        var sliderValue = testSlider.slider('getValue');

        var expectedSliderValue = initialSliderVal + initialStepVal;



        expect(sliderValue).toBe(expectedSliderValue);



        done();

      });



      keyboardEvent.keyCode = keyboardEvent.which = 39;

      handle1[0].dispatchEvent(keyboardEvent);

    });



    it("moves to the left by the 'step' value when the DOWN arrow key is pressed", function(done) {

      handle1.on("keydown", function() {

        var sliderValue = testSlider.slider('getValue');

        var expectedSliderValue = initialSliderVal - initialStepVal;



        expect(sliderValue).toBe(expectedSliderValue);



        done();

      });



      keyboardEvent.keyCode = keyboardEvent.which = 40;

      handle1[0].dispatchEvent(keyboardEvent);

    });



    it("moves to the right by the 'step' value when the UP arrow key is pressed", function(done) {

      handle1.on("keydown", function() {

        var sliderValue = testSlider.slider('getValue');

        var expectedSliderValue = initialSliderVal + initialStepVal;



        expect(sliderValue).toBe(expectedSliderValue);



        done();

      });



      keyboardEvent.keyCode = keyboardEvent.which = 38;

      handle1[0].dispatchEvent(keyboardEvent);

    });

  });



  describe("For a range slider (regardless of 'orientation')", function() {



    beforeEach(function() {

      // Initialize the slider

      testSlider = $("#testSlider1").slider({

        id: 'testSlider',

        min: initialMinVal,

        max: initialMaxVal,

        step: initialStepVal,

        value: [initialSliderVal, initialSliderVal]

      });

    });



    describe("when handle1 tries to overtake handle2 from the left", function() {

      beforeEach(function() {

        handle1 = $("#testSlider").find(".slider-handle:first");

        handle2 = $("#testSlider").find(".slider-handle:last");

        handle1.focus();

      });



      it("handle2 moves to the right by the step value", function(done) {

        handle1.on("keydown", function() {

          var sliderValue = testSlider.slider('getValue');

          var expectedSliderValue = initialSliderVal + initialStepVal;



          expect(sliderValue[1]).toBe(expectedSliderValue);



          done();

        });



        keyboardEvent.keyCode = keyboardEvent.which = 39;

        handle1[0].dispatchEvent(keyboardEvent);

      });



      it("handle1's value remains unchanged", function(done) {

        var sliderValue = testSlider.slider('getValue');



        handle1.on("keydown", function() {

          expect(sliderValue[0]).toBe(initialSliderVal);

          done();

        });



        keyboardEvent.keyCode = keyboardEvent.which = 39;

        handle1[0].dispatchEvent(keyboardEvent);

      });



      it("Should give focus to handle2 after overtaking from the left", function(done) {

        handle2.on("focus", function() {

          expect(true).toBe(true);

          done();

        });



        keyboardEvent.keyCode = keyboardEvent.which = 39;

        handle1[0].dispatchEvent(keyboardEvent);

      });

    });



    describe("when handle2 tries to overtake handle1 from the right", function() {

      beforeEach(function() {

        handle1 = $("#testSlider").find(".slider-handle:first");

        handle2 = $("#testSlider").find(".slider-handle:last");

        handle2.focus();

      });



      it("handle1 moves to the left by the step value", function(done) {

        handle2.on("keydown", function() {

          var sliderValue = testSlider.slider('getValue');

          var expectedSliderValue = initialSliderVal - initialStepVal;



          expect(sliderValue[0]).toBe(expectedSliderValue);



          done();

        });



        keyboardEvent.keyCode = keyboardEvent.which = 37;

        handle2[0].dispatchEvent(keyboardEvent);

      });



      it("handle2's value remains unchanged", function(done) {

        var sliderValue = testSlider.slider('getValue');



        handle2.on("keydown", function() {

          expect(sliderValue[1]).toBe(initialSliderVal);

          done();

        });



        keyboardEvent.keyCode = keyboardEvent.which = 37;

        handle2[0].dispatchEvent(keyboardEvent);

      });



      it("Should give focus to handle1 after overtaking from the right", function(done) {

        handle1.on("focus", function() {

          expect(true).toBe(true);

          done();

        });



        keyboardEvent.keyCode = keyboardEvent.which = 37;

        handle2[0].dispatchEvent(keyboardEvent);

      });

    });

  });



  describe("For the natural arrow keys", function() {

    var testCases = [{

      reversed: false,

      keyEvent: 37,

      expectedSliderValue: initialSliderVal - initialStepVal,

      orientation: 'horizontal',

      key: 'left'

    }, {

      reversed: true,

      keyEvent: 37,

      expectedSliderValue: initialSliderVal + initialStepVal,

      orientation: 'horizontal',

      key: 'left'

    }, {

      reversed: false,

      keyEvent: 39,

      expectedSliderValue: initialSliderVal + initialStepVal,

      orientation: 'horizontal',

      key: 'right'

    }, {

      reversed: true,

      keyEvent: 39,

      expectedSliderValue: initialSliderVal - initialStepVal,

      orientation: 'horizontal',

      key: 'right'

    }, {

      reversed: false,

      keyEvent: 38,

      expectedSliderValue: initialSliderVal - initialStepVal,

      orientation: 'vertical',

      key: 'up'

    }, {

      reversed: true,

      keyEvent: 38,

      expectedSliderValue: initialSliderVal + initialStepVal,

      orientation: 'vertical',

      key: 'up'

    }, {

      reversed: false,

      keyEvent: 40,

      expectedSliderValue: initialSliderVal + initialStepVal,

      orientation: 'vertical',

      key: 'down'

    }, {

      reversed: true,

      keyEvent: 40,

      expectedSliderValue: initialSliderVal - initialStepVal,

      orientation: 'vertical',

      key: 'down'

    }];

    testCases.forEach(function(testCase) {

      describe("A"+((testCase.reversed)? " reversed" : "")+testCase.orientation+" slider is used for the arrow keys", function() {

        beforeEach(function() {

          // Initialize the slider

          testSlider = $("#testSlider1").slider({

            id: 'testSlider',

            min: initialMinVal,

            max: initialMaxVal,

            step: initialStepVal,

            value: initialSliderVal,

            natural_arrow_keys: true,

            reversed: testCase.reversed,

            orientation: testCase.orientation

          });

          handle1 = $("#testSlider").find(".slider-handle:first");

          handle1.focus();

        });



        it("moves to the "+testCase.key+" by the 'step' value when the "+testCase.key+" arrow key is pressed", function(done) {

          handle1.on("keydown", function() {

            var sliderValue = testSlider.slider('getValue');

            var expectedSliderValue = testCase.expectedSliderValue;



            expect(sliderValue).toBe(expectedSliderValue);



            done();

          });





          keyboardEvent.keyCode = keyboardEvent.which = testCase.keyEvent;

          handle1[0].dispatchEvent(keyboardEvent);

        });

      });

    });

  });

});



describe("Navigating slider with the keyboard", function() {

  var mySlider;

  var keyboardEvent;

  var options;

  var $handle1;

  var $handle2;



  describe("Does not trigger 'change' event when values do not change", function() {

    var initialValues = [0, 1];



    beforeEach(function() {

      options = {

        id: 'mySlider',

        min: -100,

        max: 100,

        step: 1,

        value: initialValues,

        range: true

      };



      // Create keyboard event

      keyboardEvent = document.createEvent('Event');

      keyboardEvent.initEvent('keydown', true, true);

    });



    afterEach(function() {

      if (mySlider) {

        if (mySlider instanceof Slider) { mySlider.destroy(); }

        mySlider = null;

      }

    });



    it("Should not trigger 'change' event", function(done) {

      var hasSlideStarted = false;

      var hasChanged = false;

      options.value = [-100, 0];

      mySlider = new Slider($('#testSlider1')[0], options);

      $handle1 = $('#mySlider').find('.slider-handle:first');



      mySlider.on('slideStart', function() {

        hasSlideStarted = true;

      });



      mySlider.on('change', function() {

        hasChanged = true;

      });



      mySlider.on('slideStop', function() {

        var value = mySlider.getValue();

        expect(hasSlideStarted).toBe(true);

        expect(hasChanged).toBe(false);

        expect(value).toEqual([-100, 0]);

        done();

      });



      // Move the handle to the left

      keyboardEvent.keyCode = keyboardEvent.which = 37;

      $handle1[0].dispatchEvent(keyboardEvent);

    });



    it("Should not trigger 'change' event via `setValue()`", function(done) {

      var isSliding = false;

      var hasChanged = false;

      mySlider = new Slider($('#testSlider1')[0], options);

      $handle1 = $('#mySlider').find('.slider-handle:first');



      mySlider.on('slide', function() {

        isSliding = true;

      });



      mySlider.on('change', function() {

        hasChanged = true;

      });



      // Change both values of the range slider

      mySlider.setValue(initialValues, true, true);



      window.setTimeout(function() {

        var value = mySlider.getValue();

        expect(isSliding).toBe(true);

        expect(hasChanged).toBe(false);

        expect(value).toEqual(initialValues);

        done();

      });

    });

  });



  describe("Does trigger 'change' event when either value changes for range sliders", function() {



    beforeEach(function() {

      options = {

        id: 'mySlider',

        min: -100,

        max: 100,

        step: 1,

        value: [-10, 10],

        range: true

      };



      // Create keyboard event

      keyboardEvent = document.createEvent('Event');

      keyboardEvent.initEvent('keydown', true, true);

    });



    afterEach(function() {

      if (mySlider) {

        if (mySlider instanceof Slider) { mySlider.destroy(); }

        mySlider = null;

      }

    });



    it("Should trigger 'change' event when the moving the lower handle", function(done) {

      var hasSlideStarted = false;

      var hasChanged = false;



      mySlider = new Slider($('#testSlider1')[0], options);

      $handle1 = $('#mySlider').find('.slider-handle:first');



      mySlider.on('slideStart', function() {

        hasSlideStarted = true;

      });



      mySlider.on('change', function() {

        hasChanged = true;

      });



      mySlider.on('slideStop', function() {

        var value = mySlider.getValue();

        expect(hasSlideStarted).toBe(true);

        expect(hasChanged).toBe(true);

        expect(value).toEqual([-11, 10]);

        done();

      });



      // Move the handle to the left

      keyboardEvent.keyCode = keyboardEvent.which = 37;

      $handle1[0].dispatchEvent(keyboardEvent);

    });



    it("Should trigger 'change' event when moving the upper handle", function(done) {

      var hasSlideStarted = false;

      var hasChanged = false;



      mySlider = new Slider($('#testSlider1')[0], options);

      $handle2 = $('#mySlider').find('.slider-handle:last');



      mySlider.on('slideStart', function() {

        hasSlideStarted = true;

      });



      mySlider.on('change', function() {

        hasChanged = true;

      });



      mySlider.on('slideStop', function() {

        var value = mySlider.getValue();

        expect(hasSlideStarted).toBe(true);

        expect(hasChanged).toBe(true);

        expect(value).toEqual([-10, 11]);

        done();

      });



      // Move the handle to the right

      keyboardEvent.keyCode = keyboardEvent.which = 39;

      $handle2[0].dispatchEvent(keyboardEvent);

    });



    it("Should trigger 'change' event when both values change via `setValue()`", function(done) {

      var isSliding = false;



      mySlider = new Slider($('#testSlider1')[0], options);

      $handle2 = $('#mySlider').find('.slider-handle:last');



      mySlider.on('slide', function() {

        isSliding = true;

      });



      mySlider.on('change', function() {

        var value = mySlider.getValue();

        expect(isSliding).toBe(true);

        expect(value).toEqual([-50, 50]);

        done();

      });



      // Change both values of the range slider

      mySlider.setValue([-50, 50], true, true);

    });

  });

});



describe("Navigating range sliders with the keyboard", function() {

  var mySlider;

  var keyboardEvent;

  var options;

  var $handle1;

  var $handle2;



  describe("Range slider values", function() {



    beforeEach(function() {

      options = {

        id: 'mySlider',

        min: -100,

        max: 100,

        step: 1,

        value: [0, 1],

        range: true

      };



      // Create keyboard event

      keyboardEvent = document.createEvent('Event');

      keyboardEvent.initEvent('keydown', true, true);

    });



    afterEach(function() {

      if (mySlider) {

        if (mySlider instanceof Slider) { mySlider.destroy(); }

        mySlider = null;

      }

    });



    it("Should not go below minimum at 'slideStart'", function(done) {

      options.value = [-100, 0];

      mySlider = new Slider($('#testSlider1')[0], options);

      $handle1 = $('#mySlider').find('.slider-handle:first');



      mySlider.on('slideStart', function(newVal) {

        expect(newVal).toEqual([-100, 0]);

        done();

      });



      // Move the handle to the left

      keyboardEvent.keyCode = keyboardEvent.which = 37;



      $handle1[0].dispatchEvent(keyboardEvent);

    });



    it("Should not go above maximum at 'slideStart'", function(done) {

      options.value = [0, 100];

      mySlider = new Slider($('#testSlider1')[0], options);

      $handle2 = $('#mySlider').find('.slider-handle:last');



      mySlider.on('slideStart', function(newVal) {

        expect(newVal).toEqual([0, 100]);

        done();

      });



      // Move the handle to the right

      keyboardEvent.keyCode = keyboardEvent.which = 39;

      $handle2[0].dispatchEvent(keyboardEvent);

    });

  });

});

