text: var $ = require("jquery"),
      commons = require("./rangeSelectorParts/commons.js"),
      seriesDataSourceModule = require("viz/range_selector/series_data_source"),
      dataSourceModule = require("data/data_source/data_source"),
      _SeriesDataSource = seriesDataSourceModule.SeriesDataSource,
      dateUtils = require("core/utils/date"),
      vizMocks = require("../../helpers/vizMocks.js"),
      dataSource = vizMocks.stubClass(dataSourceModule.DataSource),
      axisModule = require("viz/axes/base_axis");
  
  QUnit.module("LoadingIndicator", commons.environment);
  
  QUnit.test("Not hide on refresh - when dataSource is not loaded", function(assert) {
      var ds = new dataSource(),
          widget = this.createWidget({ dataSource: ds }),
          spy = sinon.spy(widget, "_fulfillLoadingIndicatorHiding");
      ds.isLoaded = sinon.stub().returns(false);
      this.seriesDataSource.stub("isShowChart").returns(true);
      this.seriesDataSource.stub("getBoundRange").returns({
          arg: new commons.StubRange(),
          val: new commons.StubRange()
      });
  
      widget.option("scale", {});
  
      assert.strictEqual(spy.lastCall, null);
  });
  
  QUnit.test("Hide on refresh - when dataSource is loaded", function(assert) {
      var ds = new dataSource(),
          widget = this.createWidget({ dataSource: ds }),
          spy = sinon.spy(widget, "_fulfillLoadingIndicatorHiding");
      ds.isLoaded = sinon.stub().returns(true);
      this.seriesDataSource.stub("isShowChart").returns(true);
      this.seriesDataSource.stub("getBoundRange").returns({
          arg: new commons.StubRange(),
          val: new commons.StubRange()
      });
  
      widget.option("scale", {});
  
      assert.deepEqual(spy.lastCall.args, []);
  });
  
  var environmentWithDataSource = $.extend({}, commons.environment, {
      beforeEach: function() {
          commons.environment.beforeEach.apply(this, arguments);
          var test = this;
          seriesDataSourceModule.SeriesDataSource = function(params) {
              test.seriesDataSource = new _SeriesDataSource(params);
              return test.seriesDataSource;
          };
      }
  });
  
  QUnit.module("Initialization from dataSource", $.extend({}, environmentWithDataSource, {
      getArgRange: function() {
          return this.axis.setBusinessRange.lastCall.args[0];
      },
  
      getValRange: function() {
          return this.seriesDataSource.getBoundRange().val;
      }
  }));
  
  QUnit.test("Pass axes to seriesDataSource", function(assert) {
      axisModule.Axis.onSecondCall().returns(new this.StubAxis());
      var rangeSelector = this.createWidget({
          dataSource: [
              { x: 10, y1: 0 }
          ],
          chart: {
              series: {
                  argumentField: "x",
                  valueField: "y1"
              },
              valueAxis: {
                  categoriesSortingMethod: "categories sorting method"
              }
          }
      });
      var series = this.seriesDataSource.getSeries()[0],
          valueAxis = series.getValueAxis();
  
      assert.strictEqual(series.getArgumentAxis(), rangeSelector._axis, "argument axis passed to series");
      assert.deepEqual(valueAxis.updateOptions.lastCall.args[0], {
          isHorizontal: false,
          label: {},
          categoriesSortingMethod: "categories sorting method"
      }, "valueAxis options");
  
      assert.strictEqual(axisModule.Axis.secondCall.args[0].renderer, this.renderer);
      assert.strictEqual(axisModule.Axis.secondCall.args[0].drawingType, "linear");
      assert.strictEqual(axisModule.Axis.secondCall.args[0].axisType, "xyAxes");
  });
  
  QUnit.test("range min/max from dataSource. ticks inside data source range - take range by data source", function(assert) {
      this.createWidget({
          dataSource: [
              { t: 10, y1: 0 },
              { t: 190, y1: 8 }
          ],
          dataSourceField: "t",
          scale: {
              tickInterval: 20
          }
      });
  
      var options = this.axis.updateOptions.lastCall.args[0],
          range = this.getArgRange();
      assert.strictEqual(options.startValue, 10, "startValue");
      assert.strictEqual(options.endValue, 190, "endValue");
      assert.strictEqual(range.min, 10);
      assert.strictEqual(range.max, 190);
      assert.strictEqual(range.minVisible, 10);
      assert.strictEqual(range.maxVisible, 190);
      assert.strictEqual(this.seriesDataSource.isShowChart(), false, "isShowChart");
  });
  
  QUnit.test("range min/max from dataSource. ticks out of data source range - take range by ticks", function(assert) {
      this.createWidget({
          dataSource: [
              { t: 10, y1: 0 },
              { t: 190, y1: 8 }
          ],
          dataSourceField: "t",
          scale: {
              tickInterval: 20,
              endOnTick: true
          }
      });
  
      var options = this.axis.updateOptions.lastCall.args[0],
          range = this.getArgRange();
      assert.strictEqual(options.startValue, 0, "startValue");
      assert.strictEqual(options.endValue, 200, "endValue");
      assert.strictEqual(range.min, 0);
      assert.strictEqual(range.max, 200);
      assert.strictEqual(range.minVisible, 0);
      assert.strictEqual(range.maxVisible, 200);
      assert.strictEqual(this.seriesDataSource.isShowChart(), false, "isShowChart");
  });
  
  QUnit.test("range min/max from series", function(assert) {
      this.createWidget({
          dataSource: [
              { x: 10, y1: 0 },
              { x: 15, y1: 6 },
              { x: 20, y1: 8 },
              { x: 30, y1: 10 },
              { x: 50, y1: 16 },
              { x: 150, y1: 12 },
              { x: 180, y1: 8 }
          ],
          chart: {
              series: {
                  argumentField: "x",
                  valueField: "y1"
              }
          }
      });
  
      var options = this.axis.updateOptions.lastCall.args[0],
          argRange = this.getArgRange(),
          valRange = this.getValRange();
      assert.strictEqual(options.startValue, 10, "startValue");
      assert.strictEqual(options.endValue, 180, "endValue");
      assert.strictEqual(argRange.min, 10);
      assert.strictEqual(argRange.max, 180);
      assert.strictEqual(argRange.minVisible, 10);
      assert.strictEqual(argRange.maxVisible, 180);
      assert.strictEqual(valRange.min, 0);
      assert.strictEqual(valRange.max, 16 * 1.1);
      assert.strictEqual(valRange.minVisible, undefined);
      assert.strictEqual(valRange.maxVisible, undefined);
      assert.strictEqual(this.seriesDataSource.isShowChart(), true, "isShowChart");
  });
  
  QUnit.test("range max from series", function(assert) {
      this.createWidget({
          dataSource: [
              { x: 10, y1: 0 },
              { x: 15, y1: 6 },
              { x: 20, y1: 8 },
              { x: 30, y1: 10 },
              { x: 50, y1: 16 },
              { x: 150, y1: 12 },
              { x: 180, y1: 8 }
          ],
          scale: {
              startValue: 0
          },
          chart: {
              series: {
                  argumentField: "x",
                  valueField: "y1"
              }
          }
      });
  
      var options = this.axis.updateOptions.lastCall.args[0],
          argRange = this.getArgRange(),
          valRange = this.getValRange();
      assert.strictEqual(options.startValue, 0, "startValue");
      assert.strictEqual(options.endValue, 180, "endValue");
      assert.strictEqual(argRange.min, 0);
      assert.strictEqual(argRange.max, 180);
      assert.strictEqual(argRange.minVisible, 0);
      assert.strictEqual(argRange.maxVisible, 180);
      assert.strictEqual(valRange.min, 0);
      assert.strictEqual(valRange.max, 16 * 1.1);
      assert.strictEqual(valRange.minVisible, undefined);
      assert.strictEqual(valRange.maxVisible, undefined);
      assert.strictEqual(this.seriesDataSource.isShowChart(), true, "isShowChart");
  });
  
  QUnit.test("range min from series", function(assert) {
      this.createWidget({
          dataSource: [
              { x: -20, y1: 0 },
              { x: -15, y1: 6 },
              { x: -10, y1: 8 }
          ],
          scale: {
              endValue: 0
          },
          chart: {
              series: {
                  argumentField: "x",
                  valueField: "y1",
              }
          }
      });
  
      var options = this.axis.updateOptions.lastCall.args[0],
          argRange = this.getArgRange(),
          valRange = this.getValRange();
      assert.strictEqual(options.startValue, -20, "startValue");
      assert.strictEqual(options.endValue, 0, "endValue");
      assert.strictEqual(argRange.min, -20);
      assert.strictEqual(argRange.max, 0);
      assert.strictEqual(argRange.minVisible, -20);
      assert.strictEqual(argRange.maxVisible, 0);
      assert.strictEqual(valRange.min, 0);
      assert.strictEqual(valRange.max, 8 * 1.1);
      assert.strictEqual(valRange.minVisible, undefined);
      assert.strictEqual(valRange.maxVisible, undefined);
      assert.strictEqual(this.seriesDataSource.isShowChart(), true, "isShowChart");
  });
  
  QUnit.test("range min/max from several series", function(assert) {
      this.createWidget({
          dataSource: [
              { arg: 20, val: 0, arg1: 50, val1: 6 },
              { arg: 30, val: 4, arg1: 250, val1: 16 },
              { arg: 180, val: 8 }
          ],
          chart: {
              series: [{
              }, {
                  argumentField: "arg1",
                  valueField: "val1"
              }]
          }
      });
  
      var options = this.axis.updateOptions.lastCall.args[0],
          argRange = this.getArgRange(),
          valRange = this.getValRange();
      assert.strictEqual(options.startValue, 20, "startValue");
      assert.strictEqual(options.endValue, 250, "endValue");
      assert.strictEqual(argRange.min, 20);
      assert.strictEqual(argRange.max, 250);
      assert.strictEqual(argRange.minVisible, 20);
      assert.strictEqual(argRange.maxVisible, 250);
      assert.strictEqual(valRange.min, 0);
      assert.strictEqual(valRange.max, 16 * 1.1);
      assert.strictEqual(valRange.minVisible, undefined);
      assert.strictEqual(valRange.maxVisible, undefined);
      assert.strictEqual(this.seriesDataSource.isShowChart(), true, "isShowChart");
  });
  
  QUnit.test("range min/max from several series. startValue>min & endValue<max", function(assert) {
      this.createWidget({
          dataSource: [
              { arg: 20, val: 0, arg1: 50, val1: 6 },
              { arg: 30, val: 4, arg1: 250, val1: 16 },
              { arg: 180, val: 8 }
          ],
          chart: {
              series: [{
              }, {
                  argumentField: "arg1",
                  valueField: "val1"
              }]
          },
          scale: {
              startValue: 50,
              endValue: 100
          }
      });
  
      var options = this.axis.updateOptions.lastCall.args[0],
          argRange = this.getArgRange(),
          valRange = this.getValRange();
      assert.strictEqual(options.startValue, 50, "startValue");
      assert.strictEqual(options.endValue, 100, "endValue");
      assert.strictEqual(argRange.min, 20);
      assert.strictEqual(argRange.max, 250);
      assert.strictEqual(argRange.minVisible, 50);
      assert.strictEqual(argRange.maxVisible, 100);
      assert.strictEqual(valRange.min, 0);
      assert.strictEqual(valRange.max, 16 * 1.1);
      assert.strictEqual(valRange.minVisible, undefined);
      assert.strictEqual(valRange.maxVisible, undefined);
      assert.strictEqual(this.seriesDataSource.isShowChart(), true, "isShowChart");
  });
  
  QUnit.test("translator interval if series arg interval < tickInterval", function(assert) {
      this.createWidget({
          dataSource: [
              { x: 10, y1: 0 },
              { x: 15, y1: 6 },
              { x: 20, y1: 8 },
              { x: 30, y1: 10 },
              { x: 50, y1: 16 },
              { x: 150, y1: 12 },
              { x: 180, y1: 8 }
          ],
          scale: {
              minorTickInterval: 0,
              tickInterval: 10
          },
          chart: {
              series: {
                  argumentField: "x",
                  valueField: "y1",
              }
          }
      });
  
      assert.strictEqual(this.getArgRange().interval, 5);
  });
  
  QUnit.test("translator interval if series arg interval > tickInterval (axisDivisionFactor is not defined)", function(assert) {
      this.createWidget({
          dataSource: [
              { x: 10, y1: 0 },
              { x: 15, y1: 6 },
              { x: 20, y1: 8 },
              { x: 30, y1: 10 },
              { x: 50, y1: 16 },
              { x: 150, y1: 12 },
              { x: 180, y1: 8 }
          ],
          scale: {
              tickInterval: 1,
              minorTickInterval: 0
          },
          chart: {
              series: {
                  argumentField: "x",
                  valueField: "y1"
              }
          }
      });
  
      assert.strictEqual(this.getArgRange().interval, 1);
  });
  
  QUnit.test("translator interval if series arg interval > tickInterval (axisDivisionFactor is defined)", function(assert) {
      this.createWidget({
          dataSource: [
              { x: 10, y1: 0 },
              { x: 15, y1: 6 },
              { x: 20, y1: 8 },
              { x: 30, y1: 10 },
              { x: 50, y1: 16 },
              { x: 150, y1: 12 },
              { x: 180, y1: 8 }
          ],
          scale: {
              tickInterval: 1,
              axisDivisionFactor: 70,
              minorTickInterval: 0
          },
          chart: {
              series: {
                  argumentField: "x",
                  valueField: "y1"
              }
          }
      });
  
      assert.strictEqual(this.getArgRange().interval, 5);
  });
  
  QUnit.test("translator interval if series arg interval > minorTickInterval", function(assert) {
      this.createWidget({
          dataSource: [
              { x: 10, y1: 0 },
              { x: 15, y1: 6 },
              { x: 20, y1: 8 },
              { x: 30, y1: 10 },
              { x: 50, y1: 16 },
              { x: 150, y1: 12 },
              { x: 180, y1: 8 }
          ],
          scale: {
              tickInterval: 2,
              minorTickInterval: 1
          },
          chart: {
              series: {
                  argumentField: "x",
                  valueField: "y1"
              }
          }
      });
  
      assert.strictEqual(this.getArgRange().interval, 1);
  });
  
  QUnit.test("translator interval for datetime", function(assert) {
      this.createWidget({
          dataSource: [
              { x: new Date(2011, 1, 1), y1: 0 },
              { x: new Date(2011, 1, 10), y1: 6 }
          ],
          scale: {
              valueType: "datetime",
              minorTickInterval: { hours: 12 },
              tickInterval: "day"
          },
          chart: {
              series: {
                  argumentField: "x",
                  valueField: "y1",
              }
          }
      });
  
      assert.strictEqual(this.getArgRange().interval, dateUtils.dateToMilliseconds({ hours: 12 }));
  });
  
  QUnit.test("range, logarithmic scale", function(assert) {
      this.createWidget({
          dataSource: [
              { x: 0.01, y1: 0 },
              { x: 0.1, y1: 6 },
              { x: 1, y1: 8 },
              { x: 10, y1: 10 },
              { x: 100, y1: 16 },
              { x: 1000, y1: 12 },
              { x: 10000, y1: 8 }
          ],
          chart: {
              series: {
                  argumentField: "x",
                  valueField: "y1"
              }
          },
          scale: {
              type: "logarithmic",
              logarithmBase: 10
          }
      });
  
      var options = this.axis.updateOptions.lastCall.args[0],
          range = this.getArgRange();
      assert.strictEqual(options.startValue, 0.01);
      assert.strictEqual(options.endValue, 10000);
      assert.strictEqual(range.min, 0.01);
      assert.strictEqual(range.max, 10000);
      assert.strictEqual(range.minVisible, 0.01);
      assert.strictEqual(range.maxVisible, 10000);
      assert.strictEqual(range.axisType, "logarithmic");
      assert.strictEqual(range.base, 10);
  });
  
  QUnit.test("range, not logarithmic scale", function(assert) {
      this.createWidget({
          dataSource: [
              { x: 0.01, y1: 0 },
              { x: 0.1, y1: 6 },
              { x: 1, y1: 8 },
              { x: 10, y1: 10 },
              { x: 100, y1: 16 },
              { x: 1000, y1: 12 },
              { x: 10000, y1: 8 }
          ],
          chart: {
              series: {
                  argumentField: "x",
                  valueField: "y1"
              }
          },
          scale: {
              type: "continuous",
              logarithmBase: 10
          }
      });
  
      var options = this.axis.updateOptions.lastCall.args[0],
          range = this.getArgRange();
      assert.strictEqual(options.startValue, 0.01);
      assert.strictEqual(options.endValue, 10000);
      assert.strictEqual(range.min, 0.01);
      assert.strictEqual(range.max, 10000);
      assert.strictEqual(range.minVisible, 0.01);
      assert.strictEqual(range.maxVisible, 10000);
      assert.strictEqual(range.axisType, "continuous");
      assert.strictEqual(range.base, undefined);
  });
  
  QUnit.test("range, discrete scale", function(assert) {
      this.createWidget({
          dataSource: [
              { x: "a1", y: 1 },
              { x: "a2", y: 2 },
              { x: "a3", y: 3 },
              { x: "a4", y: 4 }
          ],
          chart: {
              series: {
                  argumentField: "x",
                  valueField: "y"
              }
          }
      });
  
      var options = this.axis.updateOptions.lastCall.args[0],
          range = this.getArgRange();
      assert.strictEqual(options.startValue, "a1");
      assert.strictEqual(options.endValue, "a4");
      assert.strictEqual(range.axisType, "discrete");
      assert.deepEqual(range.categories, ["a1", "a2", "a3", "a4"]);
  });
  
  QUnit.test("range, discrete scale with start/end values", function(assert) {
      this.createWidget({
          dataSource: [
              { x: "a1", y: 1 },
              { x: "a2", y: 2 },
              { x: "a3", y: 3 },
              { x: "a4", y: 4 },
              { x: "a5", y: 5 }
          ],
          scale: {
              startValue: "a2",
              endValue: "a4"
          },
          chart: {
              series: {
                  argumentField: "x",
                  valueField: "y"
              }
          }
      });
  
      var options = this.axis.updateOptions.lastCall.args[0],
          range = this.getArgRange();
      assert.strictEqual(options.startValue, "a2");
      assert.strictEqual(options.endValue, "a4");
      assert.strictEqual(range.axisType, "discrete");
      assert.strictEqual(range.min, "a2");
      assert.strictEqual(range.max, "a4");
      assert.strictEqual(range.minVisible, "a2");
      assert.strictEqual(range.maxVisible, "a4");
  });
  
  QUnit.test("range, discrete scale with start/end values without dataSource", function(assert) {
      this.createWidget({
          scale: {
              startValue: "a1",
              endValue: "a2"
          }
      });
  
      var options = this.axis.updateOptions.lastCall.args[0],
          range = this.getArgRange();
      assert.strictEqual(options.startValue, "a1");
      assert.strictEqual(options.endValue, "a2");
      assert.strictEqual(range.axisType, "discrete");
      assert.strictEqual(range.min, "a1");
      assert.strictEqual(range.max, "a2");
      assert.deepEqual(range.categories, ["a1", "a2"]);
  });
  
  QUnit.test("range, discrete scale with categories in scale options", function(assert) {
      this.createWidget({
          scale: {
              startValue: "a2",
              endValue: "a4",
              categories: ["a1", "a2", "a3", "a4", "a5"]
          }
      });
  
      var options = this.axis.updateOptions.lastCall.args[0],
          range = this.getArgRange();
      assert.strictEqual(options.startValue, "a2");
      assert.strictEqual(options.endValue, "a4");
      assert.strictEqual(range.axisType, "discrete");
      assert.strictEqual(range.min, "a2");
      assert.strictEqual(range.max, "a4");
      assert.deepEqual(range.categories, ["a1", "a2", "a3", "a4", "a5"]);
  });
  
  QUnit.test("categories axis. range with startValue, without endValue", function(assert) {
      this.createWidget({
          scale: {
              startValue: "a1"
          }
      });
  
      var options = this.axis.updateOptions.lastCall.args[0],
          range = this.getArgRange();
      assert.strictEqual(options.startValue, undefined, "start value");
      assert.strictEqual(options.endValue, undefined, "end value");
      assert.strictEqual(range.axisType, "discrete");
      assert.strictEqual(range.min, "a1");
      assert.strictEqual(range.max, undefined);
      assert.strictEqual(range.isEmpty(), true);
  });
  
  QUnit.test("categories axis. range with endValue, without startValue", function(assert) {
      this.createWidget({
          scale: {
              endValue: "a2"
          }
      });
  
      var options = this.axis.updateOptions.lastCall.args[0],
          range = this.getArgRange();
      assert.strictEqual(options.startValue, undefined, "start value");
      assert.strictEqual(options.endValue, undefined, "end value");
      assert.strictEqual(range.axisType, "discrete");
      assert.strictEqual(range.min, undefined);
      assert.strictEqual(range.max, "a2");
      assert.strictEqual(range.isEmpty(), true);
  });
  
  QUnit.test("categories axis. range with startValue, without endValue (with categories)", function(assert) {
      this.createWidget({
          scale: {
              categories: ["a0", "a1", "a2", "a3"],
              startValue: "a1"
          }
      });
  
      var options = this.axis.updateOptions.lastCall.args[0],
          range = this.getArgRange();
      assert.strictEqual(options.startValue, "a1", "start value");
      assert.strictEqual(options.endValue, "a3", "end value");
      assert.strictEqual(range.axisType, "discrete");
      assert.strictEqual(range.min, "a1");
      assert.strictEqual(range.max, undefined);
      assert.deepEqual(range.categories, ["a0", "a1", "a2", "a3"]);
  });
  
  QUnit.test("categories axis. range with endValue, without startValue (with categories)", function(assert) {
      this.createWidget({
          scale: {
              categories: ["a0", "a1", "a2", "a3"],
              endValue: "a2"
          }
      });
  
      var options = this.axis.updateOptions.lastCall.args[0],
          range = this.getArgRange();
      assert.strictEqual(options.startValue, "a0", "start value");
      assert.strictEqual(options.endValue, "a2", "end value");
      assert.strictEqual(range.axisType, "discrete");
      assert.strictEqual(range.min, undefined);
      assert.strictEqual(range.max, "a2");
      assert.deepEqual(range.categories, ["a0", "a1", "a2", "a3"]);
  });
  
  QUnit.test("range, discrete scale with categories in scale options with dataSource", function(assert) {
      this.createWidget({
          dataSource: [
              { x: "a1", y: 1 }, { x: "a2", y: 2 }, { x: "a3", y: 3 }, { x: "a4", y: 4 }, { x: "a5", y: 5 }
          ],
          scale: {
              categories: ["a2", "a3", "a4"]
          },
          chart: {
              series: {
                  argumentField: "x",
                  valueField: "y"
              }
          }
      });
  
      var options = this.axis.updateOptions.lastCall.args[0],
          range = this.getArgRange();
      assert.strictEqual(options.startValue, "a2");
      assert.strictEqual(options.endValue, "a5");
      assert.strictEqual(range.axisType, "discrete");
      assert.strictEqual(range.min, "a2");
      assert.strictEqual(range.max, "a5");
      assert.deepEqual(range.categories, ["a2", "a3", "a4", "a1", "a5"]);
  });
  
  QUnit.test("range, discrete scale with categories in scale options with dataSource and start/end values", function(assert) {
      this.createWidget({
          dataSource: [
              { x: "a1", y: 1 },
              { x: "a2", y: 2 },
              { x: "a3", y: 3 },
              { x: "a4", y: 4 },
              { x: "a5", y: 5 },
              { x: "a6", y: 6 },
              { x: "a7", y: 7 }],
          scale: {
              startValue: "a3",
              endValue: "a5",
              categories: ["a2", "a3", "a4", "a5", "a6"]
          },
          chart: {
              series: {
                  argumentField: "x",
                  valueField: "y"
              }
          }
      });
  
      var options = this.axis.updateOptions.lastCall.args[0],
          range = this.getArgRange();
      assert.strictEqual(options.startValue, "a3");
      assert.strictEqual(options.endValue, "a5");
      assert.strictEqual(range.axisType, "discrete");
      assert.strictEqual(range.min, "a3");
      assert.strictEqual(range.max, "a5");
      assert.deepEqual(range.categories, ["a2", "a3", "a4", "a5", "a6", "a1", "a7"]);
  });
  
  QUnit.test("range, discrete argument with dataSource", function(assert) {
      this.createWidget({
          dataSource: [{ arg: "a1", val1: 1, val2: 2 }, { arg: "a2", val2: 3 }, { arg: "a3", val1: 3, val2: 4 }],
          chart: {
              series: [{ valueField: "val1" }, { valueField: "val2" }]
          }
      });
  
      var range = this.getArgRange();
      assert.deepEqual(range.categories, ["a1", "a2", "a3"]);
  });
  
  // T103203
  QUnit.test("pass dataType to translator", function(assert) {
      this.createWidget({
          scale: {
              startValue: new Date(2011, 1, 1),
              endValue: new Date(2011, 6, 1)
          },
          value: [new Date(2011, 1, 5),
              new Date(2011, 2, 5)]
      });
  
      assert.strictEqual(this.getArgRange().dataType, "datetime");
  });
  
  // Tests on change all first level properties (KO support) ////////////////////
  QUnit.module("Options changing", $.extend({}, environmentWithDataSource, {
      beforeEach: function() {
          environmentWithDataSource.beforeEach.apply(this, arguments);
      }
  }));
  
  QUnit.test("range without dataSource", function(assert) {
      this.createWidget();
  
      var options = this.axis.updateOptions.lastCall.args[0];
      assert.strictEqual(options.startValue, undefined);
      assert.strictEqual(options.endValue, undefined);
  });
  
  QUnit.test("range when dataSource is changed", function(assert) {
      var range = this.createWidget();
  
      range.option({ dataSource: [{ arg: 20, val: 0 }, { arg: 30, val: 4 }, { arg: 180, val: 8 }] });
  
      var options = this.axis.updateOptions.lastCall.args[0];
      assert.strictEqual(options.startValue, 20);
      assert.strictEqual(options.endValue, 180);
  });
  
  QUnit.test("range when scale is changed", function(assert) {
      var range = this.createWidget({
          scale: {
              startValue: 1,
              endValue: 5
          }
      });
  
      range.option("scale", { endValue: 10 });
  
      var options = this.axis.updateOptions.lastCall.args[0];
      assert.strictEqual(options.startValue, 1);
      assert.strictEqual(options.endValue, 10);
  });
  
  QUnit.test("range when background is changed", function(assert) {
      var range = this.createWidget({
          background: {
              image: {
                  url: "test1.png"
              }
          }
      });
  
      range.option("background", { image: { url: "test2.png" } });
  
      // assert
      var options = this.rangeView.update.lastCall.args[0];
      assert.strictEqual(options.image.url, "test2.png");
  });
  
  QUnit.test("range when several options are changed", function(assert) {
      var range = this.createWidget({
          scale: {
              startValue: 1,
              endValue: 5
          }
      });
  
      range.option({
          scale: {
              startValue: 2,
              endValue: 5
          },
          sliderMarker: { visible: false }
      });
  
      var options = this.axis.updateOptions.lastCall.args[0];
      assert.strictEqual(options.startValue, 2);
      assert.strictEqual(options.endValue, 5);
      assert.strictEqual(this.slidersController.update.lastCall.args[4].visible, false);
  });
  
  // T319043
  QUnit.test("T319043. range updating indent", function(assert) {
      var range = this.createWidget({
          indent: {
              left: 100
          }
      });
  
      range.option("indent", { left: 50 });
  
      assert.deepEqual(this.rangeView.update.lastCall.args[2], { left: 50, top: 0, width: 299, height: 24, right: 0, bottom: 0 });
  });
  
  QUnit.test("containerBackgroundColor updating", function(assert) {
      var range = this.createWidget({
          containerBackgroundColor: "red"
      });
  
      range.option("containerBackgroundColor", "green");
  
      assert.strictEqual(this.slidersController.update.lastCall.args[5].color, "green");
  });
  
  QUnit.test("containerBackgroundColor updating. shutter color was set", function(assert) {
      var range = this.createWidget({
          containerBackgroundColor: "red",
          shutter: {
              color: "white"
          }
      });
  
      range.option("containerBackgroundColor", "green");
  
      assert.strictEqual(this.slidersController.update.lastCall.args[5].color, "white");
  });
  
  QUnit.test("title updating", function(assert) {
      var title = new vizMocks.Title(),
          titleModule = require("viz/core/title");
      title.layoutOptions = function() {
          return { horizontalAlignment: "center", verticalAlignment: "top" };
      };
      title.measure = function() {
          return [100, 50];
      };
      sinon.stub(titleModule, "Title", commons.returnValue(title));
      try {
          var range = this.createWidget({
              title: "title"
          });
          title.stub("update").returns(true);
  
          range.option({ title: "new title" });
  
          assert.equal(title.move.callCount, 2);
      } finally {
          titleModule.Title.restore();
      }
  });
  
  QUnit.module("Options initialization", environmentWithDataSource);
  
  QUnit.test("init selection number precision without snapToTicks", function(assert) {
      this.createWidget({
          scale: {
              startValue: 1,
              endValue: 4
          },
          behavior: {
              snapToTicks: false
          }
      });
  
      assert.deepEqual(this.slidersController.update.lastCall.args[4].format, { type: "fixedPoint", precision: 2 });
  });
  
  QUnit.test("rangeContainer canvas after min/max calculation", function(assert) {
      this.createWidget({
          scale: {
              tickInterval: 1
          },
          dataSource: [{ arg: 20, val: 0 }]
      });
  
      assert.deepEqual(this.slidersController.update.lastCall.args[0], [0, 24]);
  });
  
  // B217680
  QUnit.test("rangeContainer canvas with big scale max value", function(assert) {
      this.createWidget({
          scale: {
              startValue: 1,
              endValue: 1000000,
              minorTickInterval: 1
          }
      });
  
      assert.deepEqual(this.slidersController.update.lastCall.args[0], [0, 24]);
  });
  
  QUnit.test('Auto format for sliderMarker when valueType is datetime, type is discrete', function(assert) {
      this.createWidget({
          scale: {
              startValue: new Date(2006, 10, 1),
              endValue: new Date(2010, 1, 1),
              type: "discrete",
              valueType: 'datetime'
          }
      });
  
      assert.strictEqual(this.slidersController.update.lastCall.args[4].format, "monthandyear", 'Slider markers auto format');
  });
  
  QUnit.test("Calculated date format for scale label and slider marker", function(assert) {
      this.createWidget({
          size: { width: 600 },
          scale: {
              startValue: new Date(2012, 2, 1),
              endValue: new Date(2012, 2, 20),
              tickInterval: { weeks: 1 },
              marker: {
                  visible: true
              }
          }
      });
  
      assert.strictEqual(this.axis.updateOptions.lastCall.args[0].label.format, "day", "scale label");
      assert.strictEqual(this.slidersController.update.lastCall.args[4].format, "shorttime", "slider marker");
  });
  
  QUnit.test('Auto format for scale when valueType is datetime, type is discrete', function(assert) {
      this.createWidget({
          scale: {
              startValue: new Date(2006, 10, 1),
              endValue: new Date(2010, 1, 1),
              type: "discrete",
              valueType: 'datetime'
          }
      });
  
      assert.strictEqual(this.slidersController.update.lastCall.args[4].format, "monthandyear", 'Slider markers auto format');
  });
  
  // B219631
  QUnit.test("Auto format when scale marker is not visible", function(assert) {
      this.createWidget({
          scale: {
              startValue: new Date(2006, 10, 1),
              endValue: new Date(2007, 5, 1),
              tickInterval: { months: 1 },
              minorTickInterval: { days: 1 },
              marker: { visible: false }
          }
      });
  
      assert.strictEqual(this.axis.updateOptions.lastCall.args[0].label.format, "monthandyear", "Scale auto format monthAndYear(Y)");
      assert.strictEqual(this.slidersController.update.lastCall.args[4].format, "shortdate", "Slider marker auto format monthAndYear(Y)");
  });
  
  // T311953
  QUnit.test("Slidermarker format have custom format", function(assert) {
      this.createWidget({
          scale: {
              startValue: new Date(2006, 10, 1),
              endValue: new Date(2007, 5, 1),
              tickInterval: { months: 1 },
              minorTickInterval: { days: 1 },
              marker: { visible: false }
          },
          sliderMarker: {
              format: "my_format"
          }
      });
  
      assert.strictEqual(this.slidersController.update.lastCall.args[4].format, 'my_format', 'Slider marker auto format monthAndYear(Y)');
  });
  
  QUnit.test("Auto format when scale marker is not visible and minorTickInterval is zero", function(assert) {
      this.createWidget({
          scale: {
              startValue: new Date(2006, 10, 1),
              endValue: new Date(2007, 5, 1),
              tickInterval: { months: 1 },
              minorTickInterval: 0,
              marker: { visible: false }
          }
      });
  
      assert.strictEqual(this.axis.updateOptions.lastCall.args[0].label.format, "monthandyear", "Scale auto format monthAndYear(Y)");
      assert.strictEqual(this.slidersController.update.lastCall.args[4].format, "monthandyear", "Slider marker auto format monthAndYear(Y)");
  });
  
  // B230196
  QUnit.test("Auto format when minorTickInterval is auto calculated", function(assert) {
      this.createWidget({
          scale: {
              startValue: new Date(2006, 10, 1),
              endValue: new Date(2007, 5, 1),
              tickInterval: { months: 1 }
          }
      });
  
      assert.strictEqual(this.axis.updateOptions.lastCall.args[0].label.format, "monthandyear", "Scale auto format monthAndYear(month)");
      assert.strictEqual(this.slidersController.update.lastCall.args[4].format, "shortdate", "Slider marker auto format monthAndYear(day)");
  });
  
  QUnit.test("Auto format for sliderMarker when minorTickInterval and tickInterval have same unit - take previous unit", function(assert) {
      this.createWidget({
          scale: {
              startValue: new Date(2006, 10, 1),
              endValue: new Date(2010, 1, 1),
              tickInterval: { months: 4 },
              minorTickInterval: { months: 2 }
          }
      });
  
      assert.strictEqual(this.slidersController.update.lastCall.args[4].format, "shortdate", 'Slider markers auto format');
  });
  
  QUnit.test("Auto format for sliderMarker when minorTickInterval and tickInterval have same unit (with marker) - take previous unit", function(assert) {
      this.createWidget({
          scale: {
              startValue: new Date(2006, 10, 1),
              endValue: new Date(2008, 1, 1),
              tickInterval: { months: 4 },
              minorTickInterval: { months: 2 },
              marker: {
                  visible: true
              }
          }
      });
  
      assert.strictEqual(this.slidersController.update.lastCall.args[4].format, "day", 'Slider markers auto format');
  });
  
  QUnit.test("Auto format for sliderMarker when minorTickInterval and tickInterval are milliseconds - take milliseconds", function(assert) {
      this.createWidget({
          scale: {
              startValue: new Date(2006, 10, 1, 1, 1, 1),
              endValue: new Date(2006, 10, 1, 1, 1, 4),
              tickInterval: { milliseconds: 500 },
              minorTickInterval: { milliseconds: 100 }
          },
          marker: {
              visible: false
          }
      });
  
      assert.strictEqual(this.slidersController.update.lastCall.args[4].format(new Date(2017, 1, 1, 1, 1, 1, 123)), "1:01:01 AM 123", 'Slider markers auto format');
  });
  
  QUnit.test("Auto format for sliderMarker when minorTickInterval and tickInterval have different units but snapToTicks true - take minorTickInterval", function(assert) {
      this.createWidget({
          behavior: {
              snapToTicks: true
          },
          scale: {
              startValue: new Date(2006, 10, 1),
              endValue: new Date(2010, 1, 1),
              tickInterval: { months: 1 },
              minorTickInterval: { days: 14 }
          }
      });
  
      assert.strictEqual(this.slidersController.update.lastCall.args[4].format, "shortdate");
  });
  
  QUnit.test("T576618. axis division factors are null, no tick intervals - correctly calculate formats", function(assert) {
      this.createWidget({
          size: { width: 600 },
          scale: {
              startValue: new Date(2012, 2, 1),
              endValue: new Date(2012, 2, 20),
              marker: {
                  visible: true
              },
              axisDivisionFactor: null,
              minorAxisDivisionFactor: null
          }
      });
  
      assert.strictEqual(this.axis.updateOptions.lastCall.args[0].label.format, "day", "scale label");
      assert.strictEqual(this.slidersController.update.lastCall.args[4].format, "shorttime", "slider marker");
  });
  
  QUnit.test("T576618. axis division factors are undefined, no tick intervals - correctly calculate formats", function(assert) {
      this.createWidget({
          size: { width: 600 },
          scale: {
              startValue: new Date(2012, 2, 1),
              endValue: new Date(2012, 2, 20),
              marker: {
                  visible: true
              },
              axisDivisionFactor: undefined,
              minorAxisDivisionFactor: undefined
          }
      });
  
      assert.strictEqual(this.axis.updateOptions.lastCall.args[0].label.format, "day", "scale label");
      assert.strictEqual(this.slidersController.update.lastCall.args[4].format, "shorttime", "slider marker");
  });
  
  
  // B251771
  QUnit.test("scale.marker.label.customizeText is not a function", function(assert) {
      this.createWidget({
          scale: {
              startValue: new Date(2010, 2, 5),
              endValue: new Date(2014, 3, 10),
              marker: {
                  label: {
                      format: "quarterAndYear",
                      customizeText: "invalid customizePoint value"
                  }
              }
          }
      });
  
      assert.ok(true);
  });
  
  QUnit.test("pass containerBackgroundColor to slidersMarker options like border color", function(assert) {
      this.createWidget({
          containerBackgroundColor: "someColor"
      });
  
      assert.strictEqual(this.slidersController.update.lastCall.args[4].borderColor, "someColor");
  });
  
  QUnit.test("passing paddingLeftRight & paddingTopBottom to slidersController", function(assert) {
      this.createWidget({
          sliderMarker: {
              paddingTopBottom: 10,
              paddingLeftRight: 10
          }
      });
  
      assert.strictEqual(this.slidersController.update.lastCall.args[4].paddingLeftRight, 10);
      assert.strictEqual(this.slidersController.update.lastCall.args[4].paddingTopBottom, 10);
  });
  
  // T402810
  QUnit.test("tickInterval less than 6 months, width enough for years - marker is visible", function(assert) {
      this.createWidget({
          size: { width: 500 },
          scale: {
              startValue: new Date(2000, 0, 1),
              endValue: new Date(2001, 11, 31),
              marker: {
                  visible: true
              }
          }
      });
  
      assert.strictEqual(this.axis.updateOptions.lastCall.args[0].marker.visible, true);
  });
  
  // T402810
  QUnit.test("tickInterval is 6 months, width enough for years - marker is NOT visible", function(assert) {
      this.createWidget({
          size: { width: 500 },
          scale: {
              startValue: new Date(2000, 0, 1),
              endValue: new Date(2001, 11, 31),
              tickInterval: { months: 6 },
              marker: {
                  visible: true
              }
          }
      });
  
      assert.strictEqual(this.axis.updateOptions.lastCall.args[0].marker.visible, false);
  });
  
  // T402810
  QUnit.test("tickInterval less than 6 months, width is NOT enough for years - marker is NOT visible", function(assert) {
      this.createWidget({
          size: { width: 500 },
          scale: {
              startValue: new Date(2000, 0, 1),
              endValue: new Date(2011, 11, 31),
              tickInterval: { months: 3 },
              marker: {
                  visible: true
              }
          }
      });
  
      assert.strictEqual(this.axis.updateOptions.lastCall.args[0].marker.visible, false);
  });
  
  // T402810
  QUnit.test("tickInterval less than 6 months, width enough for years, marker.visible = false - marker is NOT visible", function(assert) {
      this.createWidget({
          size: { width: 500 },
          scale: {
              startValue: new Date(2000, 0, 1),
              endValue: new Date(2001, 11, 31),
              marker: {
                  visible: false
              }
          }
      });
  
      assert.strictEqual(this.axis.updateOptions.lastCall.args[0].marker.visible, false);
  });
  
  