describe('for ' + name + ' Data', function () {
      let PersistedState;
      let vislibVis;
      let vis;
      let persistedState;
      const visLibParams = {
        type: 'heatmap',
        addLegend: true,
        addTooltip: true,
        colorsNumber: 4,
        colorSchema: 'Greens',
        setColorRange: false,
        percentageMode: true,
        invertColors: false,
        colorsRange: []
      };

      function generateVis(opts = {}) {
        const config = _.defaultsDeep({}, opts, visLibParams);
        vis = vislibVis(config);
        persistedState = new PersistedState();
        vis.on('brush', _.noop);
        vis.render(data, persistedState);
      }

      beforeEach(ngMock.module('kibana'));
      beforeEach(ngMock.inject(function (Private, $injector) {
        vislibVis = Private(FixturesVislibVisFixtureProvider);
        PersistedState = $injector.get('PersistedState');
        generateVis();
      }));

      afterEach(function () {
        vis.destroy();
      });

      it('category axes should be rendered in reverse order', () => {
        const renderedCategoryAxes = vis.handler.renderArray.filter(item => {
          return item.constructor && item.constructor.name === 'Axis' && item.axisConfig.get('type') === 'category';
        });
        expect(vis.handler.categoryAxes.length).to.equal(renderedCategoryAxes.length);
        expect(vis.handler.categoryAxes[0].axisConfig.get('id')).to.equal(renderedCategoryAxes[1].axisConfig.get('id'));
        expect(vis.handler.categoryAxes[1].axisConfig.get('id')).to.equal(renderedCategoryAxes[0].axisConfig.get('id'));
      });

      describe('addSquares method', function () {
        it('should append rects', function () {
          vis.handler.charts.forEach(function (chart) {
            const numOfRects = chart.chartData.series.reduce((result, series) => {
              return result + series.values.length;
            }, 0);
            expect($(chart.chartEl).find('.series rect')).to.have.length(numOfRects);
          });
        });
      });

      describe('addBarEvents method', function () {
        function checkChart(chart) {
          const rect = $(chart.chartEl).find('.series rect').get(0);

          return {
            click: !!rect.__onclick,
            mouseOver: !!rect.__onmouseover,
            // D3 brushing requires that a g element is appended that
            // listens for mousedown events. This g element includes
            // listeners, however, I was not able to test for the listener
            // function being present. I will need to update this test
            // in the future.
            brush: !!d3.select('.brush')[0][0]
          };
        }

        it('should attach the brush if data is a set of ordered dates', function () {
          vis.handler.charts.forEach(function (chart) {
            const has = checkChart(chart);
            const ordered = vis.handler.data.get('ordered');
            const date = Boolean(ordered && ordered.date);
            expect(has.brush).to.be(date);
          });
        });

        it('should attach a click event', function () {
          vis.handler.charts.forEach(function (chart) {
            const has = checkChart(chart);
            expect(has.click).to.be(true);
          });
        });

        it('should attach a hover event', function () {
          vis.handler.charts.forEach(function (chart) {
            const has = checkChart(chart);
            expect(has.mouseOver).to.be(true);
          });
        });
      });

      describe('draw method', function () {
        it('should return a function', function () {
          vis.handler.charts.forEach(function (chart) {
            expect(_.isFunction(chart.draw())).to.be(true);
          });
        });

        it('should return a yMin and yMax', function () {
          vis.handler.charts.forEach(function (chart) {
            const yAxis = chart.handler.valueAxes[0];
            const domain = yAxis.getScale().domain();

            expect(domain[0]).to.not.be(undefined);
            expect(domain[1]).to.not.be(undefined);
          });
        });
      });

      it('should define default colors', function () {
        expect(persistedState.get('vis.defaultColors')).to.not.be(undefined);
      });

      it('should set custom range', function () {
        vis.destroy();
        generateVis({
          setColorRange: true,
          colorsRange: [{ from: 0, to: 200 }, { from: 200, to: 400 }, { from: 400, to: 500 }, { from: 500, to: Infinity }]
        });
        const labels = vis.getLegendLabels();
        expect(labels[0]).to.be('0 - 200');
        expect(labels[1]).to.be('200 - 400');
        expect(labels[2]).to.be('400 - 500');
        expect(labels[3]).to.be('500 - Infinity');
      });

      it('should show correcy Y axis title', function () {
        expect(vis.handler.categoryAxes[1].axisConfig.get('title.text')).to.equal('');
      });
    });
Exemple #2
0
describe('initXAxis', function () {

  let initXAxis;

  beforeEach(ngMock.module('kibana'));
  beforeEach(ngMock.inject(function (Private) {
    initXAxis = Private(AggResponsePointSeriesInitXAxisProvider);
  }));

  let baseChart = {
    aspects: {
      x: {
        agg: {
          fieldFormatter: _.constant({}),
          write: _.constant({ params: {} }),
          type: {}
        },
        col: {
          title: 'label'
        }
      }
    }
  };

  it('sets the xAxisFormatter if the agg is not ordered', function () {
    let chart = _.cloneDeep(baseChart);
    initXAxis(chart);
    expect(chart)
      .to.have.property('xAxisLabel', 'label')
      .and.have.property('xAxisFormatter', chart.aspects.x.agg.fieldFormatter());
  });

  it('makes the chart ordered if the agg is ordered', function () {
    let chart = _.cloneDeep(baseChart);
    chart.aspects.x.agg.type.ordered = true;

    initXAxis(chart);
    expect(chart)
      .to.have.property('xAxisLabel', 'label')
      .and.have.property('xAxisFormatter', chart.aspects.x.agg.fieldFormatter())
      .and.have.property('ordered');

    expect(chart.ordered)
      .to.be.an('object')
      .and.not.have.property('interval');
  });

  it('reads the interval param from the x agg', function () {
    let chart = _.cloneDeep(baseChart);
    chart.aspects.x.agg.type.ordered = true;
    chart.aspects.x.agg.write = _.constant({ params: { interval: 10 } });

    initXAxis(chart);
    expect(chart)
      .to.have.property('xAxisLabel', 'label')
      .and.have.property('xAxisFormatter', chart.aspects.x.agg.fieldFormatter())
      .and.have.property('ordered');

    expect(chart.ordered)
      .to.be.an('object')
      .and.have.property('interval', 10);
  });
});
Exemple #3
0
describe('tabifyAggResponse Integration', function () {

  let Vis;
  let Buckets;
  let indexPattern;
  let tabifyAggResponse;

  beforeEach(ngMock.module('kibana'));
  beforeEach(ngMock.inject(function (Private, $injector) {
    tabifyAggResponse = Private(AggResponseTabifyTabifyProvider);
    Vis = Private(VisProvider);
    indexPattern = Private(FixturesStubbedLogstashIndexPatternProvider);
  }));

  function normalizeIds(vis) {
    vis.aggs.forEach(function (agg, i) {
      agg.id = 'agg_' + (i + 1);
    });
  }

  it('transforms a simple response properly', function () {
    var vis = new Vis(indexPattern, {
      type: 'histogram',
      aggs: []
    });
    normalizeIds(vis);

    var resp = tabifyAggResponse(vis, fixtures.metricOnly, { canSplit: false });

    expect(resp).to.not.have.property('tables');
    expect(resp).to.have.property('rows').and.property('columns');
    expect(resp.rows).to.have.length(1);
    expect(resp.columns).to.have.length(1);

    expect(resp.rows[0]).to.eql([1000]);
    expect(resp.columns[0]).to.have.property('aggConfig', vis.aggs[0]);
  });

  describe('transforms a complex response', function () {
    this.slow(1000);

    let vis;
    let avg;
    let ext;
    let src;
    let os;
    let esResp;

    beforeEach(function () {
      vis = new Vis(indexPattern, {
        type: 'pie',
        aggs: [
          { type: 'avg', schema: 'metric', params: { field: 'bytes' } },
          { type: 'terms', schema: 'split', params: { field: 'extension' } },
          { type: 'terms', schema: 'segment', params: { field: 'geo.src' } },
          { type: 'terms', schema: 'segment', params: { field: 'machine.os' } }
        ]
      });
      normalizeIds(vis);

      avg = vis.aggs[0];
      ext = vis.aggs[1];
      src = vis.aggs[2];
      os = vis.aggs[3];

      esResp = _.cloneDeep(fixtures.threeTermBuckets);
      // remove the buckets for css              in MX
      esResp.aggregations.agg_2.buckets[1].agg_3.buckets[0].agg_4.buckets = [];
    });

    // check that the root table group is formed properly, then pass
    // each table to expectExtensionSplit, along with the expectInnerTables()
    // function.
    function expectRootGroup(rootTableGroup, expectInnerTables) {
      expect(rootTableGroup).to.have.property('tables');

      var tables = rootTableGroup.tables;
      expect(tables).to.be.an('array').and.have.length(3);
      expectExtensionSplit(tables[0], 'png', expectInnerTables);
      expectExtensionSplit(tables[1], 'css', expectInnerTables);
      expectExtensionSplit(tables[2], 'html', expectInnerTables);
    }

    // check that the tableGroup for the extension agg was formed properly
    // then call expectTable() on each table inside. it should validate that
    // each table is formed properly
    function expectExtensionSplit(tableGroup, key, expectTable) {
      expect(tableGroup).to.have.property('tables');
      expect(tableGroup).to.have.property('aggConfig', ext);
      expect(tableGroup).to.have.property('key', key);
      expect(tableGroup.tables).to.be.an('array').and.have.length(1);

      tableGroup.tables.forEach(function (table) {
        expectTable(table, key);
      });
    }

    // check that the columns of a table are formed properly
    function expectColumns(table, aggs) {
      expect(table.columns).to.be.an('array').and.have.length(aggs.length);
      aggs.forEach(function (agg, i) {
        expect(table.columns[i]).to.have.property('aggConfig', agg);
      });
    }

    // check that a row has expected values
    function expectRow(row, asserts) {
      expect(row).to.be.an('array');
      expect(row).to.have.length(asserts.length);
      asserts.forEach(function (assert, i) {
        assert(row[i]);
      });
    }

    // check for two character country code
    function expectCountry(val) {
      expect(val).to.be.a('string');
      expect(val).to.have.length(2);
    }

    // check for an empty cell
    function expectEmpty(val) {
      expect(val)
      .to.be('');
    }

    // check for an OS term
    function expectOS(val) {
      expect(val)
      .to.match(/^(win|mac|linux)$/);
    }

    // check for something like an average bytes result
    function expectAvgBytes(val) {
      expect(val).to.be.a('number');
      expect(val === 0 || val > 1000).to.be.ok();
    }

    // create an assert that checks for an expected value
    function expectVal(expected) {
      return function (val) {
        expect(val).to.be(expected);
      };
    }

    it('for non-hierarchical vis', function () {
      // the default for a non-hierarchical vis is to display
      // only complete rows, and only put the metrics at the end.

      vis.isHierarchical = _.constant(false);
      var tabbed = tabifyAggResponse(vis, esResp);

      expectRootGroup(tabbed, function expectTable(table, splitKey) {
        expectColumns(table, [src, os, avg]);

        table.rows.forEach(function (row) {
          if (splitKey === 'css' && row[0] === 'MX') {
            throw new Error('expected the MX row in the css table to be removed');
          } else {
            expectRow(row, [
              expectCountry,
              expectOS,
              expectAvgBytes
            ]);
          }
        });
      });
    });

    it('for hierarchical vis, with partial rows', function () {
      // since we have partialRows we expect that one row will have some empty
      // values, and since the vis is hierarchical and we are NOT using
      // minimalColumns we should expect the partial row to be completely after
      // the existing bucket and it's metric

      vis.isHierarchical = _.constant(true);
      var tabbed = tabifyAggResponse(vis, esResp, {
        partialRows: true
      });

      expectRootGroup(tabbed, function expectTable(table, splitKey) {
        expectColumns(table, [src, avg, os, avg]);

        table.rows.forEach(function (row) {
          if (splitKey === 'css' && row[0] === 'MX') {
            expectRow(row, [
              expectCountry,
              expectAvgBytes,
              expectEmpty,
              expectEmpty
            ]);
          } else {
            expectRow(row, [
              expectCountry,
              expectAvgBytes,
              expectOS,
              expectAvgBytes
            ]);
          }
        });
      });
    });

    it('for hierarchical vis, with partial rows, and minimal columns', function () {
      // since we have partialRows we expect that one row has some empty
      // values, and since the vis is hierarchical and we are displaying using
      // minimalColumns, we should expect the partial row to have a metric at
      // the end

      vis.isHierarchical = _.constant(true);
      var tabbed = tabifyAggResponse(vis, esResp, {
        partialRows: true,
        minimalColumns: true
      });

      expectRootGroup(tabbed, function expectTable(table, splitKey) {
        expectColumns(table, [src, os, avg]);

        table.rows.forEach(function (row) {
          if (splitKey === 'css' && row[0] === 'MX') {
            expectRow(row, [
              expectCountry,
              expectEmpty,
              expectVal(9299)
            ]);
          } else {
            expectRow(row, [
              expectCountry,
              expectOS,
              expectAvgBytes
            ]);
          }
        });
      });
    });

    it('for non-hierarchical vis, minimal columns set to false', function () {
      // the reason for this test is mainly to check that setting
      // minimalColumns = false on a non-hierarchical vis doesn't
      // create metric columns after each bucket

      vis.isHierarchical = _.constant(false);
      var tabbed = tabifyAggResponse(vis, esResp, {
        minimalColumns: false
      });

      expectRootGroup(tabbed, function expectTable(table, splitKey) {
        expectColumns(table, [src, os, avg]);

        table.rows.forEach(function (row) {
          expectRow(row, [
            expectCountry,
            expectOS,
            expectAvgBytes
          ]);
        });
      });
    });
  });
});
Exemple #4
0
  describe('Heatmaps', function () {
    beforeEach(ngMock.module('MarkerFactory'));
    beforeEach(ngMock.inject(function (Private) {
      var MarkerClass = Private(VislibVisualizationsMarkerTypesHeatmapProvider);
      markerLayer = createMarker(MarkerClass);
    }));

    describe('dataToHeatArray', function () {
      var max;

      beforeEach(function () {
        max = mapData.properties.allmax;
      });

      it('should return an array or values for each feature', function () {
        var arr = markerLayer._dataToHeatArray(max);
        expect(arr).to.be.an('array');
        expect(arr).to.have.length(mapData.features.length);

      });

      it('should return an array item with lat, lng, metric for each feature', function () {
        _.times(3, function () {
          var arr = markerLayer._dataToHeatArray(max);
          var index = _.random(mapData.features.length - 1);
          var feature = mapData.features[index];
          var featureValue = feature.properties.value;
          var featureArr = feature.geometry.coordinates.slice(0).concat(featureValue);
          expect(arr[index]).to.eql(featureArr);
        });
      });

      it('should return an array item with lat, lng, normalized metric for each feature', function () {
        _.times(5, function () {
          markerLayer._attr.heatNormalizeData = true;

          var arr = markerLayer._dataToHeatArray(max);
          var index = _.random(mapData.features.length - 1);
          var feature = mapData.features[index];
          var featureValue = feature.properties.value / max;
          var featureArr = feature.geometry.coordinates.slice(0).concat(featureValue);
          expect(arr[index]).to.eql(featureArr);
        });
      });
    });

    describe('tooltipProximity', function () {
      it('should return true if feature is close enough to event latlng', function () {
        _.times(5, function () {
          var feature = _.sample(mapData.features);
          var point = markerLayer._getLatLng(feature);
          var arr = markerLayer._tooltipProximity(point, feature);
          expect(arr).to.be(true);
        });
      });

      it('should return false if feature is not close enough to event latlng', function () {
        _.times(5, function () {
          var feature = _.sample(mapData.features);
          var point = L.latLng(90, -180);
          var arr = markerLayer._tooltipProximity(point, feature);
          expect(arr).to.be(false);
        });
      });
    });

    describe('nearestFeature', function () {
      it('should return nearest geoJson feature object', function () {
        _.times(5, function () {
          var feature = _.sample(mapData.features);
          var point = markerLayer._getLatLng(feature);
          var nearestPoint = markerLayer._nearestFeature(point);
          expect(nearestPoint).to.equal(feature);
        });
      });
    });

    describe('getLatLng', function () {
      it('should return a leaflet latLng object', function () {
        var feature = _.sample(mapData.features);
        var latLng = markerLayer._getLatLng(feature);
        var compare = L.latLng(feature.geometry.coordinates.slice(0).reverse());
        expect(latLng).to.eql(compare);
      });

      it('should memoize the result', function () {
        var spy = sinon.spy(L, 'latLng');
        var feature = _.sample(mapData.features);

        markerLayer._getLatLng(feature);
        expect(spy.callCount).to.be(1);

        markerLayer._getLatLng(feature);
        expect(spy.callCount).to.be(1);
      });
    });
  });
describe('RegionMapsVisualizationTests', function () {

  let domNode;
  let RegionMapsVisualization;
  let Vis;
  let indexPattern;
  let vis;

  let imageComparator;

  const _makeJsonAjaxCallOld = ChoroplethLayer.prototype._makeJsonAjaxCall;

  const dummyTableGroup = {
    columns: [{
      'id': 'col-0',
      'aggConfig': {
        'id': '2',
        'enabled': true,
        'type': 'terms',
        'schema': 'segment',
        'params': { 'field': 'geo.dest', 'size': 5, 'order': 'desc', 'orderBy': '1' }
      }, 'title': 'geo.dest: Descending'
    }, {
      'id': 'col-1',
      'aggConfig': { 'id': '1', 'enabled': true, 'type': 'count', 'schema': 'metric', 'params': {} },
      'title': 'Count'
    }],
    rows: [
      { 'col-0': 'CN', 'col-1': 26 },
      { 'col-0': 'IN', 'col-1': 17 },
      { 'col-0': 'US', 'col-1': 6 },
      { 'col-0': 'DE', 'col-1': 4 },
      { 'col-0': 'BR', 'col-1': 3 }
    ]
  };

  beforeEach(ngMock.module('kibana'));

  let getManifestStub;
  beforeEach(ngMock.inject((Private, $injector) => {

    Vis = Private(visModule.VisProvider);
    RegionMapsVisualization = Private(RegionMapsVisualizationProvider);
    indexPattern = Private(LogstashIndexPatternStubProvider);

    ChoroplethLayer.prototype._makeJsonAjaxCall = async function () {
      //simulate network call
      return new Promise((resolve)=> {
        setTimeout(() => {
          resolve(worldJson);
        }, 10);
      });
    };

    const serviceSettings = $injector.get('serviceSettings');
    getManifestStub = serviceSettings.__debugStubManifestCalls(async (url) => {
      //simulate network calls
      if (url.startsWith('https://foobar')) {
        return EMS_CATALOGUE;
      } else if (url.startsWith('https://tiles.foobar')) {
        return EMS_TILES;
      } else if (url.startsWith('https://files.foobar')) {
        return EMS_FILES;
      }
    });

  }));


  afterEach(function () {
    ChoroplethLayer.prototype._makeJsonAjaxCall = _makeJsonAjaxCallOld;
    getManifestStub.removeStub();
  });


  describe('RegionMapVisualization - basics', function () {

    beforeEach(async function () {
      setupDOM('512px', '512px');

      imageComparator = new ImageComparator();


      vis = new Vis(indexPattern, {
        type: 'region_map'
      });

      vis.params.bucket = {
        accessor: 0,
      };
      vis.params.metric = {
        accessor: 1,
      };

      vis.params.selectedJoinField = { 'name': 'iso2', 'description': 'Two letter abbreviation' };
      vis.params.selectedLayer = {
        'attribution': '<p><a href="http://www.naturalearthdata.com/about/terms-of-use">Made with NaturalEarth</a> | <a href="https://www.elastic.co/elastic-maps-service">Elastic Maps Service</a></p>&#10;',
        'name': 'World Countries',
        'format': 'geojson',
        'url': 'https://vector-staging.maps.elastic.co/blob/5715999101812736?elastic_tile_service_tos=agree&my_app_version=7.0.0-alpha1',
        'fields': [{ 'name': 'iso2', 'description': 'Two letter abbreviation' }, {
          'name': 'iso3',
          'description': 'Three letter abbreviation'
        }, { 'name': 'name', 'description': 'Country name' }],
        'created_at': '2017-07-31T16:00:19.996450',
        'id': 5715999101812736,
        'layerId': 'elastic_maps_service.World Countries'
      };
    });

    afterEach(function () {
      teardownDOM();
      imageComparator.destroy();
    });


    it('should instantiate at zoom level 2', async function () {
      const regionMapsVisualization = new RegionMapsVisualization(domNode, vis);
      await regionMapsVisualization.render(dummyTableGroup, {
        resize: false,
        params: true,
        aggs: true,
        data: true,
        uiState: false
      });
      const mismatchedPixels = await compareImage(initialPng);
      regionMapsVisualization.destroy();
      expect(mismatchedPixels).to.be.lessThan(PIXEL_DIFF);
    });

    it('should update after resetting join field', async function () {
      const regionMapsVisualization = new RegionMapsVisualization(domNode, vis);
      await regionMapsVisualization.render(dummyTableGroup, {
        resize: false,
        params: true,
        aggs: true,
        data: true,
        uiState: false
      });

      //this will actually create an empty image
      vis.params.selectedJoinField = { 'name': 'iso3', 'description': 'Three letter abbreviation' };
      vis.params.isDisplayWarning = false;//so we don't get notifications
      await regionMapsVisualization.render(dummyTableGroup, {
        resize: false,
        params: true,
        aggs: false,
        data: false,
        uiState: false
      });

      const mismatchedPixels = await compareImage(toiso3Png);
      regionMapsVisualization.destroy();
      expect(mismatchedPixels).to.be.lessThan(PIXEL_DIFF);

    });

    it('should resize', async function () {

      const regionMapsVisualization = new RegionMapsVisualization(domNode, vis);
      await regionMapsVisualization.render(dummyTableGroup, {
        resize: false,
        params: true,
        aggs: true,
        data: true,
        uiState: false
      });

      domNode.style.width = '256px';
      domNode.style.height = '128px';
      await regionMapsVisualization.render(dummyTableGroup, {
        resize: true,
        params: false,
        aggs: false,
        data: false,
        uiState: false
      });
      const mismatchedPixelsAfterFirstResize = await compareImage(afterresizePng);

      domNode.style.width = '512px';
      domNode.style.height = '512px';
      await regionMapsVisualization.render(dummyTableGroup, {
        resize: true,
        params: false,
        aggs: false,
        data: false,
        uiState: false
      });
      const mismatchedPixelsAfterSecondResize = await compareImage(initialPng);

      regionMapsVisualization.destroy();
      expect(mismatchedPixelsAfterFirstResize).to.be.lessThan(PIXEL_DIFF);
      expect(mismatchedPixelsAfterSecondResize).to.be.lessThan(PIXEL_DIFF);
    });

    it('should redo data', async function () {

      const regionMapsVisualization = new RegionMapsVisualization(domNode, vis);
      await regionMapsVisualization.render(dummyTableGroup, {
        resize: false,
        params: true,
        aggs: true,
        data: true,
        uiState: false
      });

      const newTableGroup = _.cloneDeep(dummyTableGroup);
      newTableGroup.rows.pop();//remove one shape

      await regionMapsVisualization.render(newTableGroup, {
        resize: false,
        params: false,
        aggs: false,
        data: true,
        uiState: false
      });
      const mismatchedPixelsAfterDataChange = await compareImage(afterdatachangePng);


      const anotherTableGroup = _.cloneDeep(newTableGroup);
      anotherTableGroup.rows.pop();//remove one shape
      domNode.style.width = '412px';
      domNode.style.height = '112px';
      await regionMapsVisualization.render(anotherTableGroup, {
        resize: true,
        params: false,
        aggs: false,
        data: true,
        uiState: false
      });
      const mismatchedPixelsAfterDataChangeAndResize = await compareImage(afterdatachangeandresizePng);

      regionMapsVisualization.destroy();
      expect(mismatchedPixelsAfterDataChange).to.be.lessThan(PIXEL_DIFF);
      expect(mismatchedPixelsAfterDataChangeAndResize).to.be.lessThan(PIXEL_DIFF);

    });

    it('should redo data and color ramp', async function () {

      const regionMapsVisualization = new RegionMapsVisualization(domNode, vis);
      await regionMapsVisualization.render(dummyTableGroup, {
        resize: false,
        params: true,
        aggs: true,
        data: true,
        uiState: false
      });

      const newTableGroup = _.cloneDeep(dummyTableGroup);
      newTableGroup.rows.pop();//remove one shape
      vis.params.colorSchema = 'Blues';
      await regionMapsVisualization.render(newTableGroup, {
        resize: false,
        params: true,
        aggs: false,
        data: true,
        uiState: false
      });
      const mismatchedPixelsAfterDataAndColorChange = await compareImage(aftercolorchangePng);

      regionMapsVisualization.destroy();
      expect(mismatchedPixelsAfterDataAndColorChange).to.be.lessThan(PIXEL_DIFF);

    });


    it('should zoom and center elsewhere', async function () {

      vis.params.mapZoom = 4;
      vis.params.mapCenter = [36, -85];
      const regionMapsVisualization = new RegionMapsVisualization(domNode, vis);
      await regionMapsVisualization.render(dummyTableGroup, {
        resize: false,
        params: true,
        aggs: true,
        data: true,
        uiState: false
      });

      const mismatchedPixels = await compareImage(changestartupPng);
      regionMapsVisualization.destroy();

      expect(mismatchedPixels).to.be.lessThan(PIXEL_DIFF);

    });


  });


  async function compareImage(expectedImageSource) {
    const elementList = domNode.querySelectorAll('canvas');
    expect(elementList.length).to.equal(1);
    const firstCanvasOnMap = elementList[0];
    return imageComparator.compareImage(firstCanvasOnMap, expectedImageSource, THRESHOLD);
  }


  function setupDOM(width, height) {
    domNode = document.createElement('div');
    domNode.style.top = '0';
    domNode.style.left = '0';
    domNode.style.width = width;
    domNode.style.height = height;
    domNode.style.position = 'fixed';
    domNode.style.border = '1px solid blue';
    domNode.style['pointer-events'] = 'none';
    document.body.appendChild(domNode);
  }

  function teardownDOM() {
    domNode.innerHTML = '';
    document.body.removeChild(domNode);
  }

});
Exemple #6
0
describe('Vislib xAxis Class Test Suite', function () {
  let Axis;
  let persistedState;
  let xAxis;
  let el;
  let fixture;
  let VisConfig;
  const data = {
    hits: 621,
    ordered: {
      date: true,
      interval: 30000,
      max: 1408734982458,
      min: 1408734082458
    },
    series: [
      {
        label: 'Count',
        values: [
          {
            x: 1408734060000,
            y: 8
          },
          {
            x: 1408734090000,
            y: 23
          },
          {
            x: 1408734120000,
            y: 30
          },
          {
            x: 1408734150000,
            y: 28
          },
          {
            x: 1408734180000,
            y: 36
          },
          {
            x: 1408734210000,
            y: 30
          },
          {
            x: 1408734240000,
            y: 26
          },
          {
            x: 1408734270000,
            y: 22
          },
          {
            x: 1408734300000,
            y: 29
          },
          {
            x: 1408734330000,
            y: 24
          }
        ]
      }
    ],
    xAxisFormatter: function (thing) {
      return new Date(thing);
    },
    xAxisLabel: 'Date Histogram',
    yAxisLabel: 'Count'
  };

  beforeEach(ngMock.module('kibana'));
  beforeEach(ngMock.inject(function (Private, $injector) {
    persistedState = new ($injector.get('PersistedState'))();
    Axis = Private(VislibLibAxisProvider);
    VisConfig = Private(VislibVisConfig);

    el = d3.select('body').append('div')
      .attr('class', 'x-axis-wrapper')
      .style('height', '40px');

    fixture = el.append('div')
      .attr('class', 'x-axis-div');

    const visConfig = new VisConfig({
      type: 'histogram'
    }, data, persistedState, $('.x-axis-div')[0]);
    xAxis = new Axis(visConfig, {
      type: 'category',
      id: 'CategoryAxis-1'
    });
  }));

  afterEach(function () {
    fixture.remove();
    el.remove();
  });

  describe('render Method', function () {
    beforeEach(function () {
      xAxis.render();
    });

    it('should append an svg to div', function () {
      expect(el.selectAll('svg').length).to.be(1);
    });

    it('should append a g element to the svg', function () {
      expect(el.selectAll('svg').select('g').length).to.be(1);
    });

    it('should append ticks with text', function () {
      expect(!!el.selectAll('svg').selectAll('.tick text')).to.be(true);
    });
  });

  describe('getScale, getDomain, getTimeDomain, and getRange Methods', function () {
    let timeScale;
    let width;
    let range;

    beforeEach(function () {
      width = $('.x-axis-div').width();
      xAxis.getAxis(width);
      timeScale = xAxis.getScale();
      range = xAxis.axisScale.getRange(width);
    });

    it('should return a function', function () {
      expect(_.isFunction(timeScale)).to.be(true);
    });

    it('should return the correct domain', function () {
      expect(_.isDate(timeScale.domain()[0])).to.be(true);
      expect(_.isDate(timeScale.domain()[1])).to.be(true);
    });

    it('should return the min and max dates', function () {
      expect(timeScale.domain()[0].toDateString()).to.be(new Date(1408734060000).toDateString());
      expect(timeScale.domain()[1].toDateString()).to.be(new Date(1408734330000).toDateString());
    });

    it('should return the correct range', function () {
      expect(range[0]).to.be(0);
      expect(range[1]).to.be(width);
    });
  });

  describe('getOrdinalDomain Method', function () {
    let ordinalScale;
    let ordinalDomain;
    let width;

    beforeEach(function () {
      width = $('.x-axis-div').width();
      xAxis.ordered = null;
      xAxis.axisConfig.ordered = null;
      xAxis.getAxis(width);
      ordinalScale = xAxis.getScale();
      ordinalDomain = ordinalScale.domain(['this', 'should', 'be', 'an', 'array']);
    });

    it('should return an ordinal scale', function () {
      expect(ordinalDomain.domain()[0]).to.be('this');
      expect(ordinalDomain.domain()[4]).to.be('array');
    });

    it('should return an array of values', function () {
      expect(_.isArray(ordinalDomain.domain())).to.be(true);
    });
  });

  describe('getXScale Method', function () {
    let width;
    let xScale;

    beforeEach(function () {
      width = $('.x-axis-div').width();
      xAxis.getAxis(width);
      xScale = xAxis.getScale();
    });

    it('should return a function', function () {
      expect(_.isFunction(xScale)).to.be(true);
    });

    it('should return a domain', function () {
      expect(_.isDate(xScale.domain()[0])).to.be(true);
      expect(_.isDate(xScale.domain()[1])).to.be(true);
    });

    it('should return a range', function () {
      expect(xScale.range()[0]).to.be(0);
      expect(xScale.range()[1]).to.be(width);
    });
  });

  describe('getXAxis Method', function () {
    let width;

    beforeEach(function () {
      width = $('.x-axis-div').width();
      xAxis.getAxis(width);
    });

    it('should create an getScale function on the xAxis class', function () {
      expect(_.isFunction(xAxis.getScale())).to.be(true);
    });
  });

  describe('draw Method', function () {
    it('should be a function', function () {
      expect(_.isFunction(xAxis.draw())).to.be(true);
    });
  });
});
Exemple #7
0
describe('AggParams class', function () {

  let AggParams;
  let BaseAggParam;
  let FieldAggParam;
  let OptionedAggParam;
  let RegexAggParam;

  beforeEach(ngMock.module('kibana'));
  // stub out the param classes before we get the AggParams
  beforeEach(ngMock.inject(require('./utils/_stub_agg_params')));
  // fetch out deps
  beforeEach(ngMock.inject(function (Private) {
    AggParams = Private(AggTypesAggParamsProvider);
    BaseAggParam = Private(AggTypesParamTypesBaseProvider);
    FieldAggParam = Private(AggTypesParamTypesFieldProvider);
    OptionedAggParam = Private(AggTypesParamTypesOptionedProvider);
    RegexAggParam = Private(AggTypesParamTypesRegexProvider);
  }));

  describe('constructor args', function () {
    it('accepts an array of param defs', function () {
      const params = [
        { name: 'one' },
        { name: 'two' }
      ];
      const aggParams = new AggParams(params);

      expect(aggParams).to.have.length(params.length);
      expect(aggParams).to.be.an(Array);
      expect(aggParams.byName).to.have.keys(['one', 'two']);
    });
  });

  describe('AggParam creation', function () {
    it('Uses the FieldAggParam class for params with the name "field"', function () {
      const params = [
        { name: 'field' }
      ];
      const aggParams = new AggParams(params);

      expect(aggParams).to.have.length(params.length);
      expect(aggParams[0]).to.be.a(FieldAggParam);
    });

    it('Uses the OptionedAggParam class for params of type "optioned"', function () {
      const params = [
        {
          name: 'interval',
          type: 'optioned'
        }
      ];
      const aggParams = new AggParams(params);

      expect(aggParams).to.have.length(params.length);
      expect(aggParams[0]).to.be.a(OptionedAggParam);
    });

    it('Uses the RegexAggParam class for params of type "regex"', function () {
      const params = [
        {
          name: 'exclude',
          type: 'regex'
        }
      ];
      const aggParams = new AggParams(params);

      expect(aggParams).to.have.length(params.length);
      expect(aggParams[0]).to.be.a(RegexAggParam);
    });

    it('Always converts the params to a BaseAggParam', function () {
      const params = [
        {
          name: 'height',
          editor: '<blink>high</blink>'
        },
        {
          name: 'weight',
          editor: '<blink>big</blink>'
        },
        {
          name: 'waist',
          editor: '<blink>small</blink>'
        }
      ];
      const aggParams = new AggParams(params);

      expect(BaseAggParam).to.have.property('callCount', params.length);
      expect(FieldAggParam).to.have.property('callCount', 0);
      expect(OptionedAggParam).to.have.property('callCount', 0);

      expect(aggParams).to.have.length(params.length);
      aggParams.forEach(function (aggParam) {
        expect(aggParam).to.be.a(BaseAggParam);
      });
    });
  });
});
Exemple #8
0
  describe('mapScript()', function () {
    let mapScript;
    let $rootScope;

    beforeEach(ngMock.module(
      'kibana',
      'kibana/courier',
      function ($provide) {
        $provide.service('courier', require('fixtures/mock_courier'));
      }
    ));

    beforeEach(ngMock.inject(function (Private, _$rootScope_) {
      $rootScope = _$rootScope_;
      mapScript = Private(FilterBarLibMapScriptProvider);
    }));

    it('should return the key and value for matching filters', function (done) {
      const filter = {
        meta: { index: 'logstash-*', field: 'script number' },
        script: { script: { inline: 'doc["script number"].value * 5', params: { value: 35 } } }
      };
      mapScript(filter).then(function (result) {
        expect(result).to.have.property('key', 'script number');
        expect(result).to.have.property('value', '35');
        done();
      });
      $rootScope.$apply();
    });

    it('should return undefined for none matching', function (done) {
      const filter = { meta: { index: 'logstash-*' }, query: { query_string: { query: 'foo:bar' } } };
      mapScript(filter).catch(function (result) {
        expect(result).to.be(filter);
        done();
      });
      $rootScope.$apply();
    });

    it('should return a value for a range/histogram filter from a scripted field', (done) => {
      const filter = {
        meta: {
          index: 'logstash-*',
          formattedValue: '1,000.00 to 2,000.00',
          field: 'script number'
        },
        script: {
          script: {
            params: {
              gte: 1000,
              lt: 2000,
              value: '>=1,000.00 <2,000.00'
            }
          }
        }
      };
      mapScript(filter).then((result) => {
        expect(result).to.have.property('value', filter.meta.formattedValue);
        done();
      });
      $rootScope.$apply();
    });
  });
describe('buildHierarchicalData', function () {
  let Vis;
  let indexPattern;
  let responseHandler;

  beforeEach(ngMock.module('kibana'));
  beforeEach(ngMock.inject(function (Private) {
    Vis = Private(VisProvider);
    indexPattern = Private(FixturesStubbedLogstashIndexPatternProvider);
    responseHandler = Private(VislibSlicesResponseHandlerProvider).handler;
  }));

  const buildHierarchicalData = async (aggs, response) => {
    const vis = new Vis(indexPattern, { type: 'histogram',  aggs: aggs });
    vis.isHierarchical = () => true;
    const data = tabifyAggResponse(vis.aggs, response, { metricsAtAllLevels: true });
    return await responseHandler(data);
  };

  describe('metric only', function () {
    let results;

    beforeEach(async function () {
      const aggs = [{
        id: 'agg_1',
        schema: 'metric',
        type: 'avg',
        params: {
          field: 'bytes',
        }
      }];
      results = await buildHierarchicalData(aggs, fixtures.metricOnly);
    });

    it('should set the slices with one child to a consistent label', function () {
      const checkLabel = 'Average bytes';
      expect(results).to.have.property('slices');
      expect(results.slices).to.have.property('children');
      expect(results.slices.children).to.have.length(1);
      expect(results.slices.children[0]).to.have.property('name', checkLabel);
      expect(results.slices.children[0]).to.have.property('size', 412032);
      expect(results).to.have.property('names');
      expect(results.names).to.eql([checkLabel]);
      expect(results).to.have.property('raw');
      expect(results.raw).to.have.property('rows');
      expect(results.raw.rows).to.have.length(1);
    });

  });

  describe('rows and columns', function () {
    let results;

    it('should set the rows', async function () {
      const aggs = [{
        id: 'agg_2',
        type: 'terms',
        schema: 'split',
        params: {
          field: 'extension',
        }
      }, {
        id: 'agg_3',
        type: 'terms',
        schema: 'group',
        params: {
          field: 'geo.src',
        }
      }];
      results = await buildHierarchicalData(aggs, fixtures.threeTermBuckets);
      expect(results).to.have.property('rows');
    });

    it('should set the columns', async function () {
      const aggs = [{
        id: 'agg_2',
        type: 'terms',
        schema: 'split',
        params: {
          row: false,
          field: 'extension',
        }
      }, {
        id: 'agg_3',
        type: 'terms',
        schema: 'group',
        params: {
          field: 'geo.src',
        }
      }];
      results = await buildHierarchicalData(aggs, fixtures.threeTermBuckets);
      expect(results).to.have.property('columns');
    });

  });

  describe('threeTermBuckets', function () {
    let results;

    beforeEach(async function () {
      const aggs = [{
        id: 'agg_1',
        type: 'avg',
        schema: 'metric',
        params: {
          field: 'bytes',
        }
      }, {
        id: 'agg_2',
        type: 'terms',
        schema: 'split',
        params: {
          field: 'extension',
        }
      }, {
        id: 'agg_3',
        type: 'terms',
        schema: 'group',
        params: {
          field: 'geo.src',
        }
      }, {
        id: 'agg_4',
        type: 'terms',
        schema: 'group',
        params: {
          field: 'machine.os',
        }
      }];
      results = await buildHierarchicalData(aggs, fixtures.threeTermBuckets);
    });

    it('should set the hits attribute for the results', function () {
      expect(results).to.have.property('rows');
      _.each(results.rows, function (item) {
        expect(item).to.have.property('names');
        expect(item).to.have.property('slices');
        expect(item.slices).to.have.property('children');
      });
    });

    it('should set the parent of the first item in the split', function () {
      expect(results).to.have.property('rows');
      expect(results.rows).to.have.length(3);
      expect(results.rows[0]).to.have.property('slices');
      expect(results.rows[0].slices).to.have.property('children');
      expect(results.rows[0].slices.children).to.have.length(2);
      expect(results.rows[0].slices.children[0]).to.have.property('aggConfigResult');
      expect(results.rows[0].slices.children[0].aggConfigResult.$parent.$parent).to.have.property('key', 'png');
    });

  });

  describe('oneHistogramBucket', function () {
    let results;

    beforeEach(async function () {
      const aggs = [{
        id: 'agg_2',
        type: 'histogram',
        schema: 'group',
        params: {
          field: 'bytes',
          interval: 8192
        }
      }];
      results = await buildHierarchicalData(aggs, fixtures.oneHistogramBucket);
    });

    it('should set the hits attribute for the results', function () {
      expect(results).to.have.property('slices');
      expect(results.slices).to.property('children');
      expect(results).to.have.property('names');
      expect(results.names).to.have.length(6);
      expect(results).to.have.property('raw');
    });


  });

  describe('oneRangeBucket', function () {
    let results;

    beforeEach(async function () {
      const aggs = [{
        id: 'agg_2',
        type: 'range',
        schema: 'group',
        params: {
          field: 'bytes',
        }
      }];
      results = await buildHierarchicalData(aggs, fixtures.oneRangeBucket);
    });

    it('should set the hits attribute for the results', function () {
      expect(results).to.have.property('slices');
      expect(results.slices).to.property('children');
      expect(results).to.have.property('names');
      expect(results.names).to.have.length(2);
      expect(results).to.have.property('raw');
    });

  });

  describe('oneFilterBucket', function () {
    let results;

    beforeEach(async function () {
      const aggs = [{
        id: 'agg_2',
        type: 'filters',
        schema: 'group',
        params: {
          field: 'geo.src',
          filters: [ { label: 'type:apache' }, { label: 'type:nginx' } ]
        }
      }];
      results = await buildHierarchicalData(aggs, fixtures.oneFilterBucket);
    });

    it('should set the hits attribute for the results', function () {
      expect(results).to.have.property('slices');
      expect(results).to.have.property('names');
      expect(results.names).to.have.length(2);
      expect(results).to.have.property('raw');
    });

  });

});
Exemple #10
0
  describe('interval.toIndexList()', function () {

    let intervals;
    beforeEach(ngMock.module('kibana'));
    beforeEach(ngMock.inject(function (Private) {
      intervals = Private(IndexPatternsIntervalsProvider);
    }));

    it('should return correct indices for hourly [logstash-]YYYY.MM.DD.HH', function () {
      var start = moment.utc('2014-01-01T07:00:00Z');
      var end = moment.utc('2014-01-01T08:30:00Z');
      var interval = { name: 'hours', startOf: 'hour', display: 'Hourly' };
      var list = intervals.toIndexList('[logstash-]YYYY.MM.DD.HH', interval, start, end);
      expect(list).to.eql([
        {
          index: 'logstash-2014.01.01.07',
          min: moment.utc('2014-01-01T07:00:00').valueOf(),
          max: moment.utc('2014-01-01T07:59:59.999').valueOf(),
        },
        {
          index: 'logstash-2014.01.01.08',
          min: moment.utc('2014-01-01T08:00:00').valueOf(),
          max: moment.utc('2014-01-01T08:59:59.999').valueOf(),
        }
      ]);
    });

    it('should return correct indices for daily [logstash-]YYYY.MM.DD', function () {
      var start = moment(1418244231248);
      var end = moment(1418849261281);
      var interval = { name: 'days', startOf: 'day', display: 'Daily' };
      var list = intervals.toIndexList('[logstash-]YYYY.MM.DD', interval, start, end);
      expect(list).to.eql([
        {
          index: 'logstash-2014.12.10',
          min: moment.utc('2014-12-10T00:00:00').valueOf(),
          max: moment.utc('2014-12-10T23:59:59.999').valueOf(),
        },
        {
          index: 'logstash-2014.12.11',
          min: moment.utc('2014-12-11T00:00:00').valueOf(),
          max: moment.utc('2014-12-11T23:59:59.999').valueOf(),
        },
        {
          index: 'logstash-2014.12.12',
          min: moment.utc('2014-12-12T00:00:00').valueOf(),
          max: moment.utc('2014-12-12T23:59:59.999').valueOf(),
        },
        {
          index: 'logstash-2014.12.13',
          min: moment.utc('2014-12-13T00:00:00').valueOf(),
          max: moment.utc('2014-12-13T23:59:59.999').valueOf(),
        },
        {
          index: 'logstash-2014.12.14',
          min: moment.utc('2014-12-14T00:00:00').valueOf(),
          max: moment.utc('2014-12-14T23:59:59.999').valueOf(),
        },
        {
          index: 'logstash-2014.12.15',
          min: moment.utc('2014-12-15T00:00:00').valueOf(),
          max: moment.utc('2014-12-15T23:59:59.999').valueOf(),
        },
        {
          index: 'logstash-2014.12.16',
          min: moment.utc('2014-12-16T00:00:00').valueOf(),
          max: moment.utc('2014-12-16T23:59:59.999').valueOf(),
        },
        {
          index: 'logstash-2014.12.17',
          min: moment.utc('2014-12-17T00:00:00').valueOf(),
          max: moment.utc('2014-12-17T23:59:59.999').valueOf(),
        },
      ]);
    });

    it('should return correct indices for monthly [logstash-]YYYY.MM', function () {
      var start = moment.utc('2014-12-01');
      var end = moment.utc('2015-02-01');
      var interval = { name: 'months', startOf: 'month', display: 'Monthly' };
      var list = intervals.toIndexList('[logstash-]YYYY.MM', interval, start, end);
      expect(list).to.eql([
        {
          index: 'logstash-2014.12',
          min: moment.utc(0).year(2014).month(11).valueOf(),
          max: moment.utc(0).year(2015).month(0).subtract(1, 'ms').valueOf(),
        },
        {
          index: 'logstash-2015.01',
          min: moment.utc(0).year(2015).month(0).valueOf(),
          max: moment.utc(0).year(2015).month(1).subtract(1, 'ms').valueOf(),
        },
        {
          index: 'logstash-2015.02',
          min: moment.utc(0).year(2015).month(1).valueOf(),
          max: moment.utc(0).year(2015).month(2).subtract(1, 'ms').valueOf(),
        },
      ]);
    });

    it('should return correct indices for yearly [logstash-]YYYY', function () {
      var start = moment.utc('2014-12-01');
      var end = moment.utc('2015-02-01');
      var interval = { name: 'years', startOf: 'year', display: 'Yearly' };
      var list = intervals.toIndexList('[logstash-]YYYY', interval, start, end);
      expect(list).to.eql([
        {
          index: 'logstash-2014',
          min: moment.utc(0).year(2014).valueOf(),
          max: moment.utc(0).year(2015).subtract(1, 'ms').valueOf(),
        },
        {
          index: 'logstash-2015',
          min: moment.utc(0).year(2015).valueOf(),
          max: moment.utc(0).year(2016).subtract(1, 'ms').valueOf(),
        },
      ]);
    });

    context('with sortDirection=asc', function () {
      it('returns values in ascending order', function () {
        var start = moment.utc('2014-12-01');
        var end = moment.utc('2015-02-01');
        var interval = { name: 'years', startOf: 'year', display: 'Yearly' };
        var list = intervals.toIndexList('[logstash-]YYYY', interval, start, end, 'asc');
        expect(list).to.eql([
          {
            index: 'logstash-2014',
            min: moment.utc(0).year(2014).valueOf(),
            max: moment.utc(0).year(2015).subtract(1, 'ms').valueOf(),
          },
          {
            index: 'logstash-2015',
            min: moment.utc(0).year(2015).valueOf(),
            max: moment.utc(0).year(2016).subtract(1, 'ms').valueOf(),
          },
        ]);
      });
    });

    context('with sortDirection=desc', function () {
      it('returns values in descending order', function () {
        var start = moment.utc('2014-12-01');
        var end = moment.utc('2015-02-01');
        var interval = { name: 'years', startOf: 'year', display: 'Yearly' };
        var list = intervals.toIndexList('[logstash-]YYYY', interval, start, end, 'desc');
        expect(list).to.eql([
          {
            index: 'logstash-2015',
            min: moment.utc(0).year(2015).valueOf(),
            max: moment.utc(0).year(2016).subtract(1, 'ms').valueOf(),
          },
          {
            index: 'logstash-2014',
            min: moment.utc(0).year(2014).valueOf(),
            max: moment.utc(0).year(2015).subtract(1, 'ms').valueOf(),
          },
        ]);
      });
    });
  });
Exemple #11
0
describe('Vislib yAxis Class Test Suite', function () {
  beforeEach(ngMock.module('kibana'));

  beforeEach(ngMock.inject(function (Private) {
    Data = Private(VislibLibDataProvider);
    persistedState = new (Private(PersistedStatePersistedStateProvider))();
    YAxis = Private(VislibLibYAxisProvider);

    expect($('.y-axis-wrapper')).to.have.length(0);
  }));

  afterEach(function () {
    el.remove();
    yAxisDiv.remove();
  });

  describe('render Method', function () {
    beforeEach(function () {
      createData(defaultGraphData);
      expect(d3.select(yAxis.el).selectAll('.y-axis-div')).to.have.length(1);
      yAxis.render();
    });

    it('should append an svg to div', function () {
      expect(el.selectAll('svg').length).to.be(1);
    });

    it('should append a g element to the svg', function () {
      expect(el.selectAll('svg').select('g').length).to.be(1);
    });

    it('should append ticks with text', function () {
      expect(!!el.selectAll('svg').selectAll('.tick text')).to.be(true);
    });
  });

  describe('getYScale Method', function () {
    let yScale;
    let graphData;
    let domain;
    var height = 50;

    function checkDomain(min, max) {
      var domain = yScale.domain();
      expect(domain[0]).to.be.lessThan(min + 1);
      expect(domain[1]).to.be.greaterThan(max - 1);
      return domain;
    }

    function checkRange() {
      expect(yScale.range()[0]).to.be(height);
      expect(yScale.range()[1]).to.be(0);
    }

    describe('API', function () {
      beforeEach(function () {
        createData(defaultGraphData);
        yScale = yAxis.getYScale(height);
      });

      it('should return a function', function () {
        expect(_.isFunction(yScale)).to.be(true);
      });
    });

    describe('should return log values', function () {
      let domain;
      let extents;

      it('should return 1', function () {
        yAxis._attr.scale = 'log';
        extents = [0, 400];
        domain = yAxis._getExtents(extents);

        // Log scales have a yMin value of 1
        expect(domain[0]).to.be(1);
      });
    });

    describe('positive values', function () {
      beforeEach(function () {
        graphData = defaultGraphData;
        createData(graphData);
        yScale = yAxis.getYScale(height);
      });


      it('should have domain between 0 and max value', function () {
        var min = 0;
        var max = _.max(_.flattenDeep(graphData));
        var domain = checkDomain(min, max);
        expect(domain[1]).to.be.greaterThan(0);
        checkRange();
      });
    });

    describe('negative values', function () {
      beforeEach(function () {
        graphData = [
          [ -8, -23, -30, -28, -36, -30, -26, -22, -29, -24 ],
          [ -22, -8, -30, -4, 0, 0, -3, -22, -14, -24 ]
        ];
        createData(graphData);
        yScale = yAxis.getYScale(height);
      });

      it('should have domain between min value and 0', function () {
        var min = _.min(_.flattenDeep(graphData));
        var max = 0;
        var domain = checkDomain(min, max);
        expect(domain[0]).to.be.lessThan(0);
        checkRange();
      });
    });

    describe('positive and negative values', function () {
      beforeEach(function () {
        graphData = [
          [ 8, 23, 30, 28, 36, 30, 26, 22, 29, 24 ],
          [ 22, 8, -30, -4, 0, 0, 3, -22, 14, 24 ]
        ];
        createData(graphData);
        yScale = yAxis.getYScale(height);
      });

      it('should have domain between min and max values', function () {
        var min = _.min(_.flattenDeep(graphData));
        var max = _.max(_.flattenDeep(graphData));
        var domain = checkDomain(min, max);
        expect(domain[0]).to.be.lessThan(0);
        expect(domain[1]).to.be.greaterThan(0);
        checkRange();
      });
    });

    describe('validate user defined values', function () {
      beforeEach(function () {
        yAxis._attr.mode = 'stacked';
        yAxis._attr.setYExtents = false;
        yAxis._attr.yAxis = {};
      });

      it('should throw a NaN error', function () {
        var min = 'Not a number';
        var max = 12;

        expect(function () {
          yAxis._validateUserExtents(min, max);
        }).to.throwError();
      });

      it('should return a decimal value', function () {
        yAxis._attr.mode = 'percentage';
        yAxis._attr.setYExtents = true;
        domain = [];
        domain[0] = yAxis._attr.yAxis.min = 20;
        domain[1] = yAxis._attr.yAxis.max = 80;
        var newDomain = yAxis._validateUserExtents(domain);

        expect(newDomain[0]).to.be(domain[0] / 100);
        expect(newDomain[1]).to.be(domain[1] / 100);
      });

      it('should return the user defined value', function () {
        domain = [20, 50];
        var newDomain = yAxis._validateUserExtents(domain);

        expect(newDomain[0]).to.be(domain[0]);
        expect(newDomain[1]).to.be(domain[1]);
      });
    });

    describe('should throw an error when', function () {
      it('min === max', function () {
        var min = 12;
        var max = 12;

        expect(function () {
          yAxis._validateAxisExtents(min, max);
        }).to.throwError();
      });

      it('min > max', function () {
        var min = 30;
        var max = 10;

        expect(function () {
          yAxis._validateAxisExtents(min, max);
        }).to.throwError();
      });
    });
  });

  describe('getScaleType method', function () {
    var fnNames = ['linear', 'log', 'square root'];

    it('should return a function', function () {
      fnNames.forEach(function (fnName) {
        expect(yAxis._getScaleType(fnName)).to.be.a(Function);
      });

      // if no value is provided to the function, scale should default to a linear scale
      expect(yAxis._getScaleType()).to.be.a(Function);
    });

    it('should throw an error if function name is undefined', function () {
      expect(function () {
        yAxis._getScaleType('square');
      }).to.throwError();
    });
  });

  describe('_logDomain method', function () {
    it('should throw an error', function () {
      expect(function () {
        yAxis._logDomain(-10, -5);
      }).to.throwError();
      expect(function () {
        yAxis._logDomain(-10, 5);
      }).to.throwError();
      expect(function () {
        yAxis._logDomain(0, -5);
      }).to.throwError();
    });

    it('should return a yMin value of 1', function () {
      var yMin = yAxis._logDomain(0, 200)[0];
      expect(yMin).to.be(1);
    });
  });

  describe('getYAxis method', function () {
    let mode;
    let yMax;
    let yScale;
    beforeEach(function () {
      createData(defaultGraphData);
      mode = yAxis._attr.mode;
      yMax = yAxis.yMax;
      yScale = yAxis.getYScale;
    });

    afterEach(function () {
      yAxis._attr.mode = mode;
      yAxis.yMax = yMax;
      yAxis.getYScale = yScale;
    });

    it('should use percentage format for percentages', function () {
      yAxis._attr.mode = 'percentage';
      var tickFormat = yAxis.getYAxis().tickFormat();
      expect(tickFormat(1)).to.be('100%');
    });

    it('should use decimal format for small values', function () {
      yAxis.yMax = 1;
      var tickFormat = yAxis.getYAxis().tickFormat();
      expect(tickFormat(0.8)).to.be('0.8');
    });

    it('should throw an error if yScale is NaN', function () {
      yAxis.getYScale = function () { return NaN; };
      expect(function () {
        yAxis.getYAxis();
      }).to.throwError();
    });
  });

  describe('draw Method', function () {
    beforeEach(function () {
      createData(defaultGraphData);
    });

    it('should be a function', function () {
      expect(_.isFunction(yAxis.draw())).to.be(true);
    });
  });

  describe('tickScale Method', function () {
    beforeEach(function () {
      createData(defaultGraphData);
    });

    it('should return the correct number of ticks', function () {
      expect(yAxis.tickScale(1000)).to.be(11);
      expect(yAxis.tickScale(40)).to.be(3);
      expect(yAxis.tickScale(20)).to.be(0);
    });
  });

  describe('#tickFormat()', function () {
    var formatter = function () {};

    it('returns a basic number formatter by default', function () {
      var yAxis = buildYAxis();
      expect(yAxis.tickFormat()).to.not.be(formatter);
      expect(yAxis.tickFormat()(1)).to.be('1');
    });

    it('returns the yAxisFormatter when passed', function () {
      var yAxis = buildYAxis({
        yAxisFormatter: formatter
      });
      expect(yAxis.tickFormat()).to.be(formatter);
    });

    it('returns a percentage formatter when the vis is in percentage mode', function () {
      var yAxis = buildYAxis({
        yAxisFormatter: formatter,
        _attr: {
          mode: 'percentage'
        }
      });

      expect(yAxis.tickFormat()).to.not.be(formatter);
      expect(yAxis.tickFormat()(1)).to.be('100%');
    });
  });
});
Exemple #12
0
describe('Vislib Column Layout Test Suite', function () {
  let layoutType;
  let columnLayout;
  let el;
  const data = {
    hits: 621,
    ordered: {
      date: true,
      interval: 30000,
      max: 1408734982458,
      min: 1408734082458
    },
    series: [
      {
        label: 'Count',
        values: [
          {
            x: 1408734060000,
            y: 8
          },
          {
            x: 1408734090000,
            y: 23
          },
          {
            x: 1408734120000,
            y: 30
          },
          {
            x: 1408734150000,
            y: 28
          },
          {
            x: 1408734180000,
            y: 36
          },
          {
            x: 1408734210000,
            y: 30
          },
          {
            x: 1408734240000,
            y: 26
          },
          {
            x: 1408734270000,
            y: 22
          },
          {
            x: 1408734300000,
            y: 29
          },
          {
            x: 1408734330000,
            y: 24
          }
        ]
      }
    ],
    xAxisLabel: 'Date Histogram',
    yAxisLabel: 'Count'
  };

  beforeEach(ngMock.module('kibana'));
  beforeEach(ngMock.inject(function (Private) {
    layoutType = Private(VislibLibLayoutLayoutTypesProvider);
    el = d3.select('body').append('div').attr('class', 'visualization');
    columnLayout = layoutType.point_series(el, data);
  }));

  afterEach(function () {
    el.remove();
  });

  it('should return an array of objects', function () {
    expect(_.isArray(columnLayout)).to.be(true);
    expect(_.isObject(columnLayout[0])).to.be(true);
  });

  it('should throw an error when the wrong number or no arguments provided', function () {
    expect(function () { layoutType.point_series(el); }).to.throwError();
  });
});
Exemple #13
0
describe('Vislib Vis Type', function () {
  let VislibVisType;

  const visConfig = {
    name: 'test',
    title: 'test',
    description: 'test',
    icon: 'test',
    visConfig: { component: 'test' },
    type: { visConfig: { component: 'test' } }
  };

  beforeEach(ngMock.module('kibana'));
  beforeEach(ngMock.inject(function (Private) {
    VislibVisType = Private(VislibVisTypeProvider);
  }));

  describe('initialization', () => {
    it('should set the vislib response handler if not set', () => {
      const visType = new VislibVisType(visConfig);
      expect(visType.responseHandler).to.equal('vislib_series');
    });

    it('should not change response handler if its already set', () => {
      visConfig.responseHandler = 'none';
      const visType = new VislibVisType(visConfig);
      expect(visType.responseHandler).to.equal('none');
    });

    it('creates vislib controller', () => {
      visConfig.responseHandler = 'none';
      const visType = new VislibVisType(visConfig);
      expect(visType.visualization).to.not.be.undefined;
    });
  });

  describe('controller', function () {
    it('constructor sets vis and element properties', () => {
      visConfig.responseHandler = 'none';
      const visType = new VislibVisType(visConfig);
      const Vis = visType.visualization;
      const vis = new Vis(window.document.body, {});
      expect(vis.el).to.not.be.undefined;
      expect(vis.vis).to.not.be.undefined;
    });
  });

  describe('render method', () => {
    let vis;
    beforeEach(() => {
      visConfig.responseHandler = 'none';
      const visType = new VislibVisType(visConfig);
      const Vis = visType.visualization;
      vis = new Vis(window.document.body, { params: {} });
    });

    it('rejects if response is not provided', () => {
      vis.render().then(() => {
        expect('promise was not rejected').to.equal(false);
      }).catch(() => {});
    });

    it('creates new vislib vis', () => {
      vis.render({});
      expect(vis.vis.vislibVis).to.not.be.undefined;
    });

  });

  describe('destroy method', () => {
    let vis;
    beforeEach(() => {
      visConfig.responseHandler = 'none';
      const visType = new VislibVisType(visConfig);
      const Vis = visType.visualization;
      vis = new Vis(window.document.body, { params: {} });
    });

    it('destroys vislib vis', () => {
      vis.render({}).then(() => {
        vis.destroy();
        expect(vis.vis.vislibVis).to.be.undefined;
      });
    });
  });
});
Exemple #14
0
describe('type normalizer (castMappingType)', function () {

  let fn;
  let fields;
  beforeEach(ngMock.module('kibana'));
  beforeEach(ngMock.inject(function (Private, $injector) {
    fn = Private(IndexPatternsCastMappingTypeProvider);
  }));

  it('should be a function', function () {
    expect(fn).to.be.a(Function);
  });

  it('should have a types property', function () {
    expect(fn).to.have.property('types');
  });

  it('should cast numeric types to "number"', function () {
    var types = [
      'float',
      'double',
      'integer',
      'long',
      'short',
      'byte',
      'token_count'
    ];

    _.each(types, function (type) {
      expect(fn(type)).to.be('number');
    });
  });

  it('should treat non-numeric known types as what they are', function () {
    var types = [
      'date',
      'boolean',
      'ip',
      'attachment',
      'geo_point',
      'geo_shape',
      'murmur3',
      'string'
    ];

    _.each(types, function (type) {
      expect(fn(type)).to.be(type);
    });
  });

  it('should cast text and keyword types to "string"', function () {
    var types = [
      'keyword',
      'text'
    ];

    _.each(types, function (type) {
      expect(fn(type)).to.be('string');
    });
  });

  it('should treat everything else as a string', function () {
    expect(fn('fooTypeIsNotReal')).to.be('string');
  });

});
Exemple #15
0
describe('render_directive', function () {

  beforeEach(ngMock.module('kibana'));
  beforeEach(ngMock.inject(function ($injector) {
    $rootScope = $injector.get('$rootScope');
    $compile = $injector.get('$compile');
    init = function init(markup = '', definition = {}) {
      const $parentScope = $rootScope;

      // create the markup
      const $elem = angular.element('<render-directive>');
      $elem.html(markup);
      if (definition !== null) {
        $parentScope.definition = definition;
        $elem.attr('definition', 'definition');
      }

      // compile the directive
      $compile($elem)($parentScope);
      $parentScope.$apply();

      const $directiveScope = $elem.isolateScope();

      return { $parentScope, $directiveScope, $elem };
    };
  }));

  describe('directive requirements', function () {
    it('should throw if not given a definition', function () {
      expect(() => init('', null)).to.throwException(/must have a definition/);
    });
  });

  describe('rendering with definition', function () {
    it('should call link method', function () {
      const markup = '<p>hello world</p>';
      const definition = {
        link: sinon.stub(),
      };

      init(markup, definition);

      sinon.assert.callCount(definition.link, 1);
    });

    it('should call controller method', function () {
      const markup = '<p>hello world</p>';
      const definition = {
        controller: sinon.stub(),
      };

      init(markup, definition);

      sinon.assert.callCount(definition.controller, 1);
    });
  });

  describe('definition scope binding', function () {
    it('should accept two-way, attribute, and expression binding directives', function () {
      const $el = angular.element(`
        <render-directive
          definition="definition"
          two-way-prop="parentTwoWay"
          attr="Simple Attribute"
          expr="parentExpression()"
          >
          {{two}},{{attr}},{{expr()}}
        </render-directive>
      `);

      const $parentScope = $rootScope.$new();
      $parentScope.definition = {
        scope: {
          two: '=twoWayProp',
          attr: '@',
          expr: '&expr'
        }
      };
      $parentScope.parentTwoWay = true;
      $parentScope.parentExpression = function () {
        return !$parentScope.parentTwoWay;
      };

      $compile($el)($parentScope);
      $parentScope.$apply();

      expect($el.text().trim()).to.eql('true,Simple Attribute,false');
      $parentScope.parentTwoWay = false;
      $parentScope.$apply();
      expect($el.text().trim()).to.eql('false,Simple Attribute,true');
    });
  });
});
Exemple #16
0
describe('Promise service',  () => {
  let Promise;
  let $rootScope;

  const sandbox = sinon.createSandbox();
  function tick(ms = 0) {
    sandbox.clock.tick(ms);

    // Ugly, but necessary for promises to resolve: https://github.com/angular/angular.js/issues/12555
    $rootScope.$apply();
  }

  beforeEach(ngMock.module('kibana'));
  beforeEach(ngMock.inject(($injector) => {
    sandbox.useFakeTimers();

    Promise = $injector.get('Promise');
    $rootScope = $injector.get('$rootScope');
  }));

  afterEach(() => sandbox.restore());

  describe('Constructor',  () => {
    it('provides resolve and reject function', () => {
      const executor = sinon.stub();
      new Promise(executor);

      sinon.assert.calledOnce(executor);
      sinon.assert.calledWithExactly(executor, sinon.match.func, sinon.match.func);
    });
  });

  it('Promise.resolve', () => {
    const onResolve = sinon.stub();
    Promise.resolve(true).then(onResolve);

    tick();

    sinon.assert.calledOnce(onResolve);
    sinon.assert.calledWithExactly(onResolve, true);
  });

  describe('Promise.fromNode',  () => {
    it('creates a callback that controls a promise', () => {
      const callback = sinon.stub();
      Promise.fromNode(callback);

      tick();

      sinon.assert.calledOnce(callback);
      sinon.assert.calledWithExactly(callback, sinon.match.func);
    });

    it('rejects if the callback receives an error', () => {
      const err = new Error();
      const onReject = sinon.stub();
      Promise.fromNode(sinon.stub().yields(err)).catch(onReject);

      tick();

      sinon.assert.calledOnce(onReject);
      sinon.assert.calledWithExactly(onReject, sinon.match.same(err));
    });

    it('resolves with the second argument', () => {
      const result = {};
      const onResolve = sinon.stub();
      Promise.fromNode(sinon.stub().yields(null, result)).then(onResolve);

      tick();

      sinon.assert.calledOnce(onResolve);
      sinon.assert.calledWithExactly(onResolve, sinon.match.same(result));
    });

    it('resolves with an array if multiple arguments are received', () => {
      const result1 = {};
      const result2 = {};
      const onResolve = sinon.stub();
      Promise.fromNode(sinon.stub().yields(null, result1, result2)).then(onResolve);

      tick();

      sinon.assert.calledOnce(onResolve);
      sinon.assert.calledWithExactly(
        onResolve,
        [sinon.match.same(result1), sinon.match.same(result2)]
      );
    });

    it('resolves with an array if multiple undefined are received', () => {
      const onResolve = sinon.stub();
      Promise.fromNode(sinon.stub().yields(null, undefined, undefined)).then(onResolve);

      tick();

      sinon.assert.calledOnce(onResolve);
      sinon.assert.calledWithExactly(onResolve, [undefined, undefined]);
    });
  });

  describe('Promise.race()', () => {
    it(`resolves with the first resolved promise's value`, () => {
      const p1 = new Promise(resolve => setTimeout(resolve, 100, 1));
      const p2 = new Promise(resolve => setTimeout(resolve, 200, 2));
      const onResolve = sinon.stub();
      Promise.race([p1, p2]).then(onResolve);

      tick(200);

      sinon.assert.calledOnce(onResolve);
      sinon.assert.calledWithExactly(onResolve, 1);
    });

    it(`rejects with the first rejected promise's rejection reason`, () => {
      const p1Error = new Error('1');
      const p1 = new Promise((r, reject) => setTimeout(reject, 200, p1Error));

      const p2Error = new Error('2');
      const p2 = new Promise((r, reject) => setTimeout(reject, 100, p2Error));

      const onReject = sinon.stub();
      Promise.race([p1, p2]).catch(onReject);

      tick(200);

      sinon.assert.calledOnce(onReject);
      sinon.assert.calledWithExactly(onReject, sinon.match.same(p2Error));
    });

    it('does not wait for subsequent promises to resolve/reject', () => {
      const onP1Resolve = sinon.stub();
      const p1 = new Promise(resolve => setTimeout(resolve, 100)).then(onP1Resolve);

      const onP2Resolve = sinon.stub();
      const p2 = new Promise(resolve => setTimeout(resolve, 101)).then(onP2Resolve);

      const onResolve = sinon.stub();
      Promise.race([p1, p2]).then(onResolve);

      tick(100);

      sinon.assert.calledOnce(onResolve);
      sinon.assert.calledOnce(onP1Resolve);
      sinon.assert.callOrder(onP1Resolve, onResolve);
      sinon.assert.notCalled(onP2Resolve);
    });

    it('allows non-promises in the array', () => {
      const onResolve = sinon.stub();
      Promise.race([1, 2, 3]).then(onResolve);

      tick();

      sinon.assert.calledOnce(onResolve);
      sinon.assert.calledWithExactly(onResolve, 1);
    });

    describe('argument is undefined', () => {
      it('rejects the promise', () => {
        const football = {};
        const onReject = sinon.stub();
        Promise.race().catch(() => football).then(onReject);

        tick();

        sinon.assert.calledOnce(onReject);
        sinon.assert.calledWithExactly(onReject, sinon.match.same(football));
      });
    });

    describe('argument is a string', () => {
      it(`resolves with the first character`, () => {
        const onResolve = sinon.stub();
        Promise.race('abc').then(onResolve);

        tick();

        sinon.assert.calledOnce(onResolve);
        sinon.assert.calledWithExactly(onResolve, 'a');
      });
    });

    describe('argument is a non-iterable object', () => {
      it('reject the promise', () => {
        const football = {};
        const onReject = sinon.stub();
        Promise.race({}).catch(() => football).then(onReject);

        tick();

        sinon.assert.calledOnce(onReject);
        sinon.assert.calledWithExactly(onReject, sinon.match.same(football));
      });
    });

    describe('argument is a generator', () => {
      it('resolves with the first resolved value', () => {
        function *gen() {
          yield new Promise(resolve => setTimeout(resolve, 100, 1));
          yield new Promise(resolve => setTimeout(resolve, 200, 2));
        }

        const onResolve = sinon.stub();
        Promise.race(gen()).then(onResolve);

        tick(200);

        sinon.assert.calledOnce(onResolve);
        sinon.assert.calledWithExactly(onResolve, 1);
      });

      it('resolves with the first non-promise value', () => {
        function *gen() {
          yield 1;
          yield new Promise(resolve => setTimeout(resolve, 200, 2));
        }

        const onResolve = sinon.stub();
        Promise.race(gen()).then(onResolve);

        tick(200);

        sinon.assert.calledOnce(onResolve);
        sinon.assert.calledWithExactly(onResolve, 1);
      });

      it('iterates all values from the generator, even if one is already "resolved"', () => {
        let yieldCount = 0;
        function *gen() {
          yieldCount += 1;
          yield 1;
          yieldCount += 1;
          yield new Promise(resolve => setTimeout(resolve, 200, 2));
        }

        const onResolve = sinon.stub();
        Promise.race(gen()).then(onResolve);

        tick(200);

        sinon.assert.calledOnce(onResolve);
        sinon.assert.calledWithExactly(onResolve, 1);
        expect(yieldCount).to.be(2);
      });
    });
  });
});
Exemple #17
0
describe('getSeries', function () {
  let getSeries;

  let agg = { fieldFormatter: _.constant(_.identity) };

  beforeEach(ngMock.module('kibana'));
  beforeEach(ngMock.inject(function (Private) {
    getSeries = Private(AggResponsePointSeriesGetSeriesProvider);
  }));

  function wrapRows(row) {
    return row.map(function (v) {
      return { value: v };
    });
  }

  it('produces a single series with points for each row', function () {
    let rows = [
      [1, 2, 3],
      [1, 2, 3],
      [1, 2, 3],
      [1, 2, 3],
      [1, 2, 3]
    ].map(wrapRows);

    let chart = {
      aspects: {
        x: { i: 0 },
        y: { i: 1 },
        z: { i: 2 }
      }
    };

    let series = getSeries(rows, chart);

    expect(series)
      .to.be.an('array')
      .and.to.have.length(1);

    let siri = series[0];
    expect(siri)
      .to.be.an('object')
      .and.have.property('label', '')
      .and.have.property('values');

    expect(siri.values)
      .to.be.an('array')
      .and.have.length(5);

    siri.values.forEach(function (point) {
      expect(point)
        .to.have.property('x', 1)
        .and.property('y', 2)
        .and.property('z', 3);
    });
  });

  it('produces multiple series if there are multiple y aspects', function () {
    let rows = [
      [1, 2, 3],
      [1, 2, 3],
      [1, 2, 3],
      [1, 2, 3],
      [1, 2, 3]
    ].map(wrapRows);

    let chart = {
      aspects: {
        x: { i: 0 },
        y: [
          { i: 1, col: { title: '0' }, agg: { id: 1 } },
          { i: 2, col: { title: '1' }, agg: { id: 2 } },
        ]
      }
    };

    let series = getSeries(rows, chart);

    expect(series)
      .to.be.an('array')
      .and.to.have.length(2);

    series.forEach(function (siri, i) {
      expect(siri)
        .to.be.an('object')
        .and.have.property('label', '' + i)
        .and.have.property('values');

      expect(siri.values)
        .to.be.an('array')
        .and.have.length(5);

      siri.values.forEach(function (point) {
        expect(point)
          .to.have.property('x', 1)
          .and.property('y', i + 2);
      });
    });
  });

  it('produces multiple series if there is a series aspect', function () {
    let rows = [
      ['0', 3],
      ['1', 3],
      ['1', 'NaN'],
      ['0', 3],
      ['0', 'NaN'],
      ['1', 3],
      ['0', 3],
      ['1', 3]
    ].map(wrapRows);

    let chart = {
      aspects: {
        x: { i: -1 },
        series: { i: 0, agg: agg },
        y: { i: 1, col: { title: '0' } }
      }
    };

    let series = getSeries(rows, chart);

    expect(series)
      .to.be.an('array')
      .and.to.have.length(2);

    series.forEach(function (siri, i) {
      expect(siri)
        .to.be.an('object')
        .and.have.property('label', '' + i)
        .and.have.property('values');

      expect(siri.values)
        .to.be.an('array')
        .and.have.length(3);

      siri.values.forEach(function (point) {
        expect(point)
          .to.have.property('x', '_all')
          .and.property('y', 3);
      });
    });
  });

  it('produces multiple series if there is a series aspect and multipl y aspects', function () {
    let rows = [
      ['0', 3, 4],
      ['1', 3, 4],
      ['0', 3, 4],
      ['1', 3, 4],
      ['0', 3, 4],
      ['1', 3, 4]
    ].map(wrapRows);

    let chart = {
      aspects: {
        x: { i: -1 },
        series: { i: 0, agg: agg },
        y: [
          { i: 1, col: { title: '0' }, agg: { id: 1 } },
          { i: 2, col: { title: '1' }, agg: { id: 2 } }
        ]
      }
    };

    let series = getSeries(rows, chart);

    expect(series)
      .to.be.an('array')
      .and.to.have.length(4); // two series * two metrics

    checkSiri(series[0], '0: 0', 3);
    checkSiri(series[1], '0: 1', 4);
    checkSiri(series[2], '1: 0', 3);
    checkSiri(series[3], '1: 1', 4);

    function checkSiri(siri, label, y) {
      expect(siri)
        .to.be.an('object')
        .and.have.property('label', label)
        .and.have.property('values');

      expect(siri.values)
        .to.be.an('array')
        .and.have.length(3);

      siri.values.forEach(function (point) {
        expect(point)
          .to.have.property('x', '_all')
          .and.property('y', y);
      });
    }
  });

  it('produces a series list in the same order as its corresponding metric column', function () {
    let rows = [
      ['0', 3, 4],
      ['1', 3, 4],
      ['0', 3, 4],
      ['1', 3, 4],
      ['0', 3, 4],
      ['1', 3, 4]
    ].map(wrapRows);

    let chart = {
      aspects: {
        x: { i: -1 },
        series: { i: 0, agg: agg },
        y: [
          { i: 1, col: { title: '0' }, agg: { id: 1 } },
          { i: 2, col: { title: '1' }, agg: { id: 2 } }
        ]
      }
    };

    let series = getSeries(rows, chart);
    expect(series[0]).to.have.property('label', '0: 0');
    expect(series[1]).to.have.property('label', '0: 1');
    expect(series[2]).to.have.property('label', '1: 0');
    expect(series[3]).to.have.property('label', '1: 1');


    // switch the order of the y columns
    chart.aspects.y = chart.aspects.y.reverse();
    chart.aspects.y.forEach(function (y, i) {
      y.i = i;
    });

    let series2 = getSeries(rows, chart);
    expect(series2[0]).to.have.property('label', '0: 1');
    expect(series2[1]).to.have.property('label', '0: 0');
    expect(series2[2]).to.have.property('label', '1: 1');
    expect(series2[3]).to.have.property('label', '1: 0');
  });
});
Exemple #18
0
describe('Vislib xAxis Class Test Suite', function () {
  let XAxis;
  let Data;
  let persistedState;
  let xAxis;
  let el;
  let fixture;
  let dataObj;
  let data = {
    hits: 621,
    label: '',
    ordered: {
      date: true,
      interval: 30000,
      max: 1408734982458,
      min: 1408734082458
    },
    series: [
      {
        values: [
          {
            x: 1408734060000,
            y: 8
          },
          {
            x: 1408734090000,
            y: 23
          },
          {
            x: 1408734120000,
            y: 30
          },
          {
            x: 1408734150000,
            y: 28
          },
          {
            x: 1408734180000,
            y: 36
          },
          {
            x: 1408734210000,
            y: 30
          },
          {
            x: 1408734240000,
            y: 26
          },
          {
            x: 1408734270000,
            y: 22
          },
          {
            x: 1408734300000,
            y: 29
          },
          {
            x: 1408734330000,
            y: 24
          }
        ]
      }
    ],
    xAxisFormatter: function (thing) {
      return new Date(thing);
    },
    xAxisLabel: 'Date Histogram',
    yAxisLabel: 'Count'
  };

  beforeEach(ngMock.module('kibana'));
  beforeEach(ngMock.inject(function (Private) {
    Data = Private(VislibLibDataProvider);
    persistedState = new (Private(PersistedStatePersistedStateProvider))();
    XAxis = Private(VislibLibXAxisProvider);

    el = d3.select('body').append('div')
      .attr('class', 'x-axis-wrapper')
      .style('height', '40px');

    fixture = el.append('div')
      .attr('class', 'x-axis-div');

    dataObj = new Data(data, {}, persistedState);
    xAxis = new XAxis({
      el: $('.x-axis-div')[0],
      xValues: dataObj.xValues(),
      ordered: dataObj.get('ordered'),
      xAxisFormatter: dataObj.get('xAxisFormatter'),
      _attr: {
        margin: { top: 0, right: 0, bottom: 0, left: 0 }
      }
    });
  }));

  afterEach(function () {
    fixture.remove();
    el.remove();
  });

  describe('render Method', function () {
    beforeEach(function () {
      xAxis.render();
    });

    it('should append an svg to div', function () {
      expect(el.selectAll('svg').length).to.be(1);
    });

    it('should append a g element to the svg', function () {
      expect(el.selectAll('svg').select('g').length).to.be(1);
    });

    it('should append ticks with text', function () {
      expect(!!el.selectAll('svg').selectAll('.tick text')).to.be(true);
    });
  });

  describe('getScale, getDomain, getTimeDomain, getOrdinalDomain, and getRange Methods', function () {
    let ordered;
    let timeScale;
    let timeDomain;
    let ordinalScale;
    let ordinalDomain;
    let width;
    let range;

    beforeEach(function () {
      timeScale = xAxis.getScale();
      timeDomain = xAxis.getDomain(timeScale);
      range = xAxis.getRange(timeDomain, width);
      xAxis.ordered = {};
      ordinalScale = xAxis.getScale();
      ordinalDomain = ordinalScale.domain(['this', 'should', 'be', 'an', 'array']);
      width = $('.x-axis-div').width();
    });

    it('should return a function', function () {
      expect(_.isFunction(timeScale)).to.be(true);
      expect(_.isFunction(ordinalScale)).to.be(true);
    });

    it('should return the correct domain', function () {
      expect(_.isDate(timeDomain.domain()[0])).to.be(true);
      expect(_.isDate(timeDomain.domain()[1])).to.be(true);
    });

    it('should return the min and max dates', function () {
      expect(timeDomain.domain()[0].toDateString()).to.be(new Date(1408734060000).toDateString());
      expect(timeDomain.domain()[1].toDateString()).to.be(new Date(1408734330000).toDateString());
    });

    it('should return an ordinal scale', function () {
      expect(ordinalDomain.domain()[0]).to.be('this');
      expect(ordinalDomain.domain()[4]).to.be('array');
    });

    it('should return an array of values', function () {
      expect(_.isArray(ordinalDomain.domain())).to.be(true);
    });

    it('should return the correct range', function () {
      expect(range.range()[0]).to.be(0);
      expect(range.range()[1]).to.be(width);
    });
  });

  describe('getXScale Method', function () {
    let width;
    let xScale;

    beforeEach(function () {
      width = $('.x-axis-div').width();
      xScale = xAxis.getXScale(width);
    });

    it('should return a function', function () {
      expect(_.isFunction(xScale)).to.be(true);
    });

    it('should return a domain', function () {
      expect(_.isDate(xScale.domain()[0])).to.be(true);
      expect(_.isDate(xScale.domain()[1])).to.be(true);
    });

    it('should return a range', function () {
      expect(xScale.range()[0]).to.be(0);
      expect(xScale.range()[1]).to.be(width);
    });
  });

  describe('getXAxis Method', function () {
    let width;
    let axis;

    beforeEach(function () {
      width = $('.x-axis-div').width();
      xAxis.getXAxis(width);
    });

    it('should create an xAxis function on the xAxis class', function () {
      expect(_.isFunction(xAxis.xAxis)).to.be(true);
    });

    it('should create an xScale function on the xAxis class', function () {
      expect(_.isFunction(xAxis.xScale)).to.be(true);
    });

    it('should create an xAxisFormatter function on the xAxis class', function () {
      expect(_.isFunction(xAxis.xAxisFormatter)).to.be(true);
    });
  });

  describe('draw Method', function () {
    it('should be a function', function () {
      expect(_.isFunction(xAxis.draw())).to.be(true);
    });
  });

});
Exemple #19
0
describe('get filters', function () {
  const storeNames = {
    app: 'appState',
    global: 'globalState'
  };
  let queryFilter;
  let appState;
  let globalState;

  beforeEach(ngMock.module(
    'kibana',
    'kibana/global_state',
    function ($provide) {
      appState = new MockState({ filters: [] });
      $provide.service('getAppState', function () {
        return function () { return appState; };
      });

      globalState = new MockState({ filters: [] });
      $provide.service('globalState', function () {
        return globalState;
      });
    }
  ));

  beforeEach(ngMock.inject(function (_$rootScope_, Private) {
    queryFilter = Private(FilterBarQueryFilterProvider);
  }));

  describe('getFilters method', function () {
    let filters;

    beforeEach(function () {
      filters = [
        { query: { match: { extension: { query: 'jpg', type: 'phrase' } } } },
        { query: { match: { '@tags': { query: 'info', type: 'phrase' } } } },
        null
      ];
    });

    it('should return app and global filters', function () {
      appState.filters = [filters[0]];
      globalState.filters = [filters[1]];

      // global filters should be listed first
      let res = queryFilter.getFilters();
      expect(res[0]).to.eql(filters[1]);
      expect(res[1]).to.eql(filters[0]);

      // should return updated version of filters
      const newFilter = { query: { match: { '_type': { query: 'nginx', type: 'phrase' } } } };
      appState.filters.push(newFilter);

      res = queryFilter.getFilters();
      expect(res).to.contain(newFilter);
    });

    it('should append the state store', function () {
      appState.filters = [filters[0]];
      globalState.filters = [filters[1]];

      const res = queryFilter.getFilters();
      expect(res[0].$state.store).to.be(storeNames.global);
      expect(res[1].$state.store).to.be(storeNames.app);
    });

    it('should return non-null filters from specific states', function () {
      const states = [
        [ globalState, queryFilter.getGlobalFilters ],
        [ appState, queryFilter.getAppFilters ],
      ];

      _.each(states, function (state) {
        state[0].filters = filters.slice(0);
        expect(state[0].filters).to.contain(null);

        const res = state[1]();
        expect(res.length).to.be(state[0].filters.length);
        expect(state[0].filters).to.not.contain(null);
      });
    });

    it('should replace the state, not save it', function () {
      const states = [
        [ globalState, queryFilter.getGlobalFilters ],
        [ appState, queryFilter.getAppFilters ],
      ];

      expect(appState.save.called).to.be(false);
      expect(appState.replace.called).to.be(false);


      _.each(states, function (state) {
        expect(state[0].save.called).to.be(false);
        expect(state[0].replace.called).to.be(false);

        state[0].filters = filters.slice(0);
        state[1]();
        expect(state[0].save.called).to.be(false);
        expect(state[0].replace.called).to.be(true);
      });
    });
  });

  describe('filter reconciliation', function () {
    let filters;

    beforeEach(function () {
      filters = [
        {
          query: { match: { extension: { query: 'jpg', type: 'phrase' } } },
          meta: { negate: false, disabled: false }
        },
        {
          query: { match: { '@tags': { query: 'info', type: 'phrase' } } },
          meta: { negate: false, disabled: false }
        },
        {
          query: { match: { '_type': { query: 'nginx', type: 'phrase' } } },
          meta: { negate: false, disabled: false }
        }
      ];
    });

    it('should skip appState filters that match globalState filters', function () {
      globalState.filters = filters;
      const appFilter = _.cloneDeep(filters[1]);
      appState.filters.push(appFilter);

      // global filters should be listed first
      const res = queryFilter.getFilters();
      expect(res).to.have.length(3);
      _.each(res, function (filter) {
        expect(filter.$state.store).to.be('globalState');
      });
    });

    it('should append conflicting appState filters', function () {
      globalState.filters = filters;
      const appFilter = _.cloneDeep(filters[1]);
      appFilter.meta.negate = true;
      appState.filters.push(appFilter);

      // global filters should be listed first
      const res = queryFilter.getFilters();
      expect(res).to.have.length(4);
      expect(res.filter(function (filter) {
        return filter.$state.store === storeNames.global;
      }).length).to.be(3);
      expect(res.filter(function (filter) {
        return filter.$state.store === storeNames.app;
      }).length).to.be(1);
    });

    it('should not affect disabled filters', function () {
      // test adding to globalState
      globalState.filters = _.map(filters, function (filter) {
        const f = _.cloneDeep(filter);
        f.meta.disabled = true;
        return f;
      });
      _.each(filters, function (filter) { globalState.filters.push(filter); });
      let res = queryFilter.getFilters();
      expect(res).to.have.length(6);

      // test adding to appState
      globalState.filters = _.map(filters, function (filter) {
        const f = _.cloneDeep(filter);
        f.meta.disabled = true;
        return f;
      });
      _.each(filters, function (filter) { appState.filters.push(filter); });
      res = queryFilter.getFilters();
      expect(res).to.have.length(6);
    });
  });
});
Exemple #20
0
  describe('function fetchAnchor', function () {
    let fetchAnchor;
    let SearchSourceStub;

    beforeEach(ngMock.module(function createServiceStubs($provide) {
      $provide.value('courier', createCourierStub());
    }));

    beforeEach(ngMock.inject(function createPrivateStubs(Private) {
      SearchSourceStub = createSearchSourceStubProvider([
        { _id: 'hit1' },
      ]);
      Private.stub(SearchSourceProvider, SearchSourceStub);

      fetchAnchor = Private(fetchAnchorProvider);
    }));

    it('should use the `fetchAsRejectablePromise` method of the SearchSource', function () {
      const searchSourceStub = new SearchSourceStub();

      return fetchAnchor('INDEX_PATTERN_ID', 'UID', [{ '@timestamp': 'desc' }, { '_doc': 'asc' }])
        .then(() => {
          expect(searchSourceStub.fetchAsRejectablePromise.calledOnce).to.be(true);
        });
    });

    it('should configure the SearchSource to not inherit from the implicit root', function () {
      const searchSourceStub = new SearchSourceStub();

      return fetchAnchor('INDEX_PATTERN_ID', 'UID', [{ '@timestamp': 'desc' }, { '_doc': 'asc' }])
        .then(() => {
          const inheritsSpy = searchSourceStub.inherits;
          expect(inheritsSpy.calledOnce).to.be(true);
          expect(inheritsSpy.firstCall.args[0]).to.eql(false);
        });
    });

    it('should set the SearchSource index pattern', function () {
      const searchSourceStub = new SearchSourceStub();

      return fetchAnchor('INDEX_PATTERN_ID', 'UID', [{ '@timestamp': 'desc' }, { '_doc': 'asc' }])
        .then(() => {
          const setIndexSpy = searchSourceStub.set.withArgs('index');
          expect(setIndexSpy.calledOnce).to.be(true);
          expect(setIndexSpy.firstCall.args[1]).to.eql({ id: 'INDEX_PATTERN_ID' });
        });
    });

    it('should set the SearchSource version flag to true', function () {
      const searchSourceStub = new SearchSourceStub();

      return fetchAnchor('INDEX_PATTERN_ID', 'UID', [{ '@timestamp': 'desc' }, { '_doc': 'asc' }])
        .then(() => {
          const setVersionSpy = searchSourceStub.set.withArgs('version');
          expect(setVersionSpy.calledOnce).to.be(true);
          expect(setVersionSpy.firstCall.args[1]).to.eql(true);
        });
    });

    it('should set the SearchSource size to 1', function () {
      const searchSourceStub = new SearchSourceStub();

      return fetchAnchor('INDEX_PATTERN_ID', 'UID', [{ '@timestamp': 'desc' }, { '_doc': 'asc' }])
        .then(() => {
          const setSizeSpy = searchSourceStub.set.withArgs('size');
          expect(setSizeSpy.calledOnce).to.be(true);
          expect(setSizeSpy.firstCall.args[1]).to.eql(1);
        });
    });

    it('should set the SearchSource query to a _uid terms query', function () {
      const searchSourceStub = new SearchSourceStub();

      return fetchAnchor('INDEX_PATTERN_ID', 'UID', [{ '@timestamp': 'desc' }, { '_doc': 'asc' }])
        .then(() => {
          const setQuerySpy = searchSourceStub.set.withArgs('query');
          expect(setQuerySpy.calledOnce).to.be(true);
          expect(setQuerySpy.firstCall.args[1]).to.eql({
            query: {
              terms: {
                _uid: ['UID'],
              }
            },
            language: 'lucene'
          });
        });
    });

    it('should set the SearchSource sort order', function () {
      const searchSourceStub = new SearchSourceStub();

      return fetchAnchor('INDEX_PATTERN_ID', 'UID', [{ '@timestamp': 'desc' }, { '_doc': 'asc' }])
        .then(() => {
          const setSortSpy = searchSourceStub.set.withArgs('sort');
          expect(setSortSpy.calledOnce).to.be(true);
          expect(setSortSpy.firstCall.args[1]).to.eql([
            { '@timestamp': 'desc' },
            { '_doc': 'asc' },
          ]);
        });
    });

    it('should reject with an error when no hits were found', function () {
      const searchSourceStub = new SearchSourceStub();
      searchSourceStub._stubHits = [];

      return fetchAnchor('INDEX_PATTERN_ID', 'UID', [{ '@timestamp': 'desc' }, { '_doc': 'asc' }])
        .then(
          () => {
            expect().fail('expected the promise to be rejected');
          },
          (error) => {
            expect(error).to.be.an(Error);
          }
        );
    });

    it('should return the first hit after adding an anchor marker', function () {
      const searchSourceStub = new SearchSourceStub();
      searchSourceStub._stubHits = [
        { property1: 'value1' },
        { property2: 'value2' },
      ];

      return fetchAnchor('INDEX_PATTERN_ID', 'UID', [{ '@timestamp': 'desc' }, { '_doc': 'asc' }])
        .then((anchorDocument) => {
          expect(anchorDocument).to.have.property('property1', 'value1');
          expect(anchorDocument).to.have.property('$$_isAnchor', true);
        });
    });
  });
Exemple #21
0
describe('visualize directive', function () {
  let $rootScope;
  let $compile;
  let $scope;
  let $el;
  let Vis;
  let indexPattern;
  let fixtures;
  let searchSource;
  let appState;

  beforeEach(ngMock.module('kibana', 'kibana/table_vis'));
  beforeEach(ngMock.inject(function (Private, $injector) {
    $rootScope = $injector.get('$rootScope');
    $compile = $injector.get('$compile');
    fixtures = require('fixtures/fake_hierarchical_data');
    Vis = Private(VisProvider);
    appState = new MockState({ filters: [] });
    appState.toJSON = () => { return {}; };
    indexPattern = Private(FixturesStubbedLogstashIndexPatternProvider);
    searchSource = Private(FixturesStubbedSearchSourceProvider);

    const requiresSearch = false;
    init(new CreateVis(null, requiresSearch), fixtures.oneRangeBucket);
  }));

  afterEach(() => {
    $scope.$destroy();
  });

  // basically a parameterized beforeEach
  function init(vis, esResponse) {
    vis.aggs.forEach(function (agg, i) { agg.id = 'agg_' + (i + 1); });

    $rootScope.vis = vis;
    $rootScope.esResponse = esResponse;
    $rootScope.uiState = require('fixtures/mock_ui_state');
    $rootScope.appState = appState;
    $rootScope.appState.vis = vis.getState();
    $rootScope.searchSource = searchSource;
    $rootScope.savedObject = {
      vis: vis,
      searchSource: searchSource
    };
    $el = $('<visualize saved-obj="savedObject" ui-state="uiState" app-state="appState">');
    $compile($el)($rootScope);
    $rootScope.$apply();

    $scope = $el.isolateScope();
  }

  function CreateVis(params, requiresSearch) {
    const vis = new Vis(indexPattern, {
      type: 'table',
      params: params || {},
      aggs: [
        { type: 'count', schema: 'metric' },
        {
          type: 'range',
          schema: 'bucket',
          params: {
            field: 'bytes',
            ranges: [
              { from: 0, to: 1000 },
              { from: 1000, to: 2000 }
            ]
          }
        }
      ]
    });

    vis.type.requestHandler = requiresSearch ? 'default' : 'none';
    vis.type.responseHandler = 'none';
    vis.type.requiresSearch = false;
    return vis;
  }

  it('searchSource.onResults should not be called when requiresSearch is false', function () {
    searchSource.crankResults();
    $scope.$digest();
    expect(searchSource.getOnResultsCount()).to.be(0);
  });

  it('fetches new data on update event', () => {
    let counter = 0;
    $scope.fetch = () => { counter++; };
    $scope.vis.emit('update');
    expect(counter).to.equal(1);
  });

  it('updates the appState in editor mode on update event', () => {
    $scope.editorMode = true;
    $scope.appState.vis = {};
    $scope.vis.emit('update');
    expect($scope.appState.vis).to.not.equal({});
  });

  it('sets force flag on force event', () => {
    $scope.vis.emit('reload');
    expect($scope.vis.reload).to.equal(true);
  });

});
Exemple #22
0
describe('IndexPattern#flattenHit()', function () {
  let flattenHit;
  let config;
  let hit;

  beforeEach(ngMock.module('kibana'));
  beforeEach(ngMock.inject(function (Private, $injector) {
    const indexPattern = {
      fields: {
        byName: {
          'tags.text': { type: 'string' },
          'tags.label': { type: 'string' },
          'message': { type: 'string' },
          'geo.coordinates': { type: 'geo_point' },
          'geo.dest': { type: 'string' },
          'geo.src': { type: 'string' },
          'bytes': { type: 'number' },
          '@timestamp': { type: 'date' },
          'team': { type: 'nested' },
          'team.name': { type: 'string' },
          'team.role': { type: 'string' },
          'user': { type: 'conflict' },
          'user.name': { type: 'string' },
          'user.id': { type: 'conflict' },
          'delta': { type: 'number', scripted: true }
        }
      }
    };

    const cachedFlatten = Private(IndexPatternsFlattenHitProvider)(indexPattern);
    flattenHit = function (hit, deep = false) {
      delete hit.$$_flattened;
      return cachedFlatten(hit, deep);
    };

    config = $injector.get('config');

    hit = {
      _source: {
        message: 'Hello World',
        geo: {
          coordinates: { lat: 33.4500, lon: 112.0667 },
          dest: 'US',
          src: 'IN'
        },
        bytes: 10039103,
        '@timestamp': (new Date()).toString(),
        tags: [
          { text: 'foo', label: [ 'FOO1', 'FOO2' ] },
          { text: 'bar', label: 'BAR' }
        ],
        groups: ['loners'],
        noMapping: true,
        team: [
          { name: 'foo', role: 'leader' },
          { name: 'bar', role: 'follower' },
          { name: 'baz', role: 'party boy' },
        ],
        user: { name: 'smith', id: 123 }
      },
      fields: {
        delta: [42],
        random: [0.12345]
      }
    };
  }));

  it('flattens keys as far down as the mapping goes', function () {
    const flat = flattenHit(hit);

    expect(flat).to.have.property('geo.coordinates', hit._source.geo.coordinates);
    expect(flat).to.not.have.property('geo.coordinates.lat');
    expect(flat).to.not.have.property('geo.coordinates.lon');
    expect(flat).to.have.property('geo.dest', 'US');
    expect(flat).to.have.property('geo.src', 'IN');
    expect(flat).to.have.property('@timestamp', hit._source['@timestamp']);
    expect(flat).to.have.property('message', 'Hello World');
    expect(flat).to.have.property('bytes', 10039103);
  });

  it('flattens keys not in the mapping', function () {
    const flat = flattenHit(hit);

    expect(flat).to.have.property('noMapping', true);
    expect(flat).to.have.property('groups');
    expect(flat.groups).to.eql(['loners']);
  });

  it('flattens conflicting types in the mapping', function () {
    const flat = flattenHit(hit);

    expect(flat).to.not.have.property('user');
    expect(flat).to.have.property('user.name', hit._source.user.name);
    expect(flat).to.have.property('user.id', hit._source.user.id);
  });

  it('should preserve objects in arrays if deep argument is false', function () {
    const flat = flattenHit(hit);

    expect(flat).to.have.property('tags', hit._source.tags);
  });

  it('should expand objects in arrays if deep argument is true', function () {
    const flat = flattenHit(hit, true);

    expect(flat['tags.text']).to.be.eql([ 'foo', 'bar' ]);
  });

  it('should support arrays when expanding objects in arrays if deep argument is true', function () {
    const flat = flattenHit(hit, true);

    expect(flat['tags.label']).to.be.eql([ 'FOO1', 'FOO2', 'BAR' ]);
  });

  it('does not enter into nested fields', function () {
    const flat = flattenHit(hit);

    expect(flat).to.have.property('team', hit._source.team);
    expect(flat).to.not.have.property('team.name');
    expect(flat).to.not.have.property('team.role');
    expect(flat).to.not.have.property('team[0]');
    expect(flat).to.not.have.property('team.0');
  });

  it('unwraps script fields', function () {
    const flat = flattenHit(hit);

    expect(flat).to.have.property('delta', 42);
  });

  it('assumes that all fields are "computed fields"', function () {
    const flat = flattenHit(hit);

    expect(flat).to.have.property('random', 0.12345);
  });

  it('ignores fields that start with an _ and are not in the metaFields', function () {
    config.set('metaFields', ['_metaKey']);
    hit.fields._notMetaKey = [100];
    const flat = flattenHit(hit);
    expect(flat).to.not.have.property('_notMetaKey');
  });

  it('includes underscore-prefixed keys that are in the metaFields', function () {
    config.set('metaFields', ['_metaKey']);
    hit.fields._metaKey = [100];
    const flat = flattenHit(hit);
    expect(flat).to.have.property('_metaKey', 100);
  });

  it('adapts to changes in the metaFields', function () {
    hit.fields._metaKey = [100];

    config.set('metaFields', ['_metaKey']);
    let flat = flattenHit(hit);
    expect(flat).to.have.property('_metaKey', 100);

    config.set('metaFields', []);
    flat = flattenHit(hit);
    expect(flat).to.not.have.property('_metaKey');
  });

  it('handles fields that are not arrays, like _timestamp', function () {
    hit.fields._metaKey = 20000;
    config.set('metaFields', ['_metaKey']);
    const flat = flattenHit(hit);
    expect(flat).to.have.property('_metaKey', 20000);
  });
});
Exemple #23
0
  describe('Base Methods', function () {
    var MarkerClass;

    beforeEach(ngMock.module('MarkerFactory'));
    beforeEach(ngMock.inject(function (Private) {
      MarkerClass = Private(VislibVisualizationsMarkerTypesBaseMarkerProvider);
      markerLayer = createMarker(MarkerClass);
    }));

    describe('filterToMapBounds', function () {
      it('should not filter any features', function () {
        // set bounds to the entire world
        setBounds([-87.252, -343.828], [87.252, 343.125]);
        var boundFilter = markerLayer._filterToMapBounds();
        var mapFeature = mapData.features.filter(boundFilter);

        expect(mapFeature.length).to.equal(mapData.features.length);
      });

      it('should filter out data points that are outside of the map bounds', function () {
        // set bounds to roughly US southwest
        setBounds([31.690, -124.387], [42.324, -102.919]);
        var boundFilter = markerLayer._filterToMapBounds();
        var mapFeature = mapData.features.filter(boundFilter);

        expect(mapFeature.length).to.be.lessThan(mapData.features.length);
      });
    });

    describe('legendQuantizer', function () {
      it('should return a range of hex colors', function () {
        var minColor = markerLayer._legendQuantizer(mapData.properties.allmin);
        var maxColor = markerLayer._legendQuantizer(mapData.properties.allmax);

        expect(minColor.substring(0, 1)).to.equal('#');
        expect(minColor).to.have.length(7);
        expect(maxColor.substring(0, 1)).to.equal('#');
        expect(maxColor).to.have.length(7);
        expect(minColor).to.not.eql(maxColor);
      });

      it('should return a color with 1 color', function () {
        var geoJson = { properties: { min: 1, max: 1 } };
        markerLayer = createMarker(MarkerClass, geoJson);

        // ensure the quantizer domain is correct
        var color = markerLayer._legendQuantizer(1);
        expect(color).to.not.be(undefined);
        expect(color.substring(0, 1)).to.equal('#');

        // should always get the same color back
        _.times(5, function () {
          var num = _.random(0, 100);
          var randColor = markerLayer._legendQuantizer(0);
          expect(randColor).to.equal(color);
        });
      });
    });

    describe('applyShadingStyle', function () {
      it('should return a style object', function () {
        var style = markerLayer.applyShadingStyle(100);
        expect(style).to.be.an('object');

        var keys = _.keys(style);
        var expected = ['fillColor', 'color'];
        _.each(expected, function (key) {
          expect(keys).to.contain(key);
        });
      });

      it('should use the legendQuantizer', function () {
        var spy = sinon.spy(markerLayer, '_legendQuantizer');
        var style = markerLayer.applyShadingStyle(100);
        expect(spy.callCount).to.equal(1);
      });
    });

    describe('showTooltip', function () {
      it('should use the tooltip formatter', function () {
        var content;
        var sample = _.sample(mapData.features);

        var stub = sinon.stub(markerLayer, '_tooltipFormatter', function (val) {
          return;
        });

        markerLayer._showTooltip(sample);

        expect(stub.callCount).to.equal(1);
        expect(stub.firstCall.calledWith(sample)).to.be(true);
      });
    });

    describe('addLegend', function () {
      var addToSpy;
      var leafletControlStub;

      beforeEach(function () {
        addToSpy = sinon.spy();
        leafletControlStub = sinon.stub(L, 'control', function (options) {
          return {
            addTo: addToSpy
          };
        });
      });

      it('should do nothing if there is already a legend', function () {
        markerLayer._legend = { legend: 'exists' }; // anything truthy

        markerLayer.addLegend();
        expect(leafletControlStub.callCount).to.equal(0);
      });

      it('should create a leaflet control', function () {
        markerLayer.addLegend();
        expect(leafletControlStub.callCount).to.equal(1);
        expect(addToSpy.callCount).to.equal(1);
        expect(addToSpy.firstCall.calledWith(markerLayer.map)).to.be(true);
        expect(markerLayer._legend).to.have.property('onAdd');
      });

      it('should use the value formatter', function () {
        var formatterSpy = sinon.spy(markerLayer, '_valueFormatter');
        // called twice for every legend color defined
        var expectedCallCount = markerLayer._legendColors.length * 2;

        markerLayer.addLegend();
        var legend = markerLayer._legend.onAdd();

        expect(formatterSpy.callCount).to.equal(expectedCallCount);
        expect(legend).to.be.a(HTMLDivElement);
      });
    });
  });
Exemple #24
0
describe('config component', function () {
  let config;
  let $scope;

  beforeEach(ngMock.module('kibana'));
  beforeEach(ngMock.inject(function ($injector) {
    config = $injector.get('config');
    $scope = $injector.get('$rootScope');
  }));

  describe('#get', function () {
    it('gives access to config values', function () {
      expect(config.get('dateFormat')).to.be.a('string');
    });

    it('supports the default value overload', function () {
      // default values are consumed and returned atomically
      expect(config.get('obscureProperty', 'default')).to.be('default');
      // default values are consumed only if setting was previously unset
      expect(config.get('obscureProperty', 'another')).to.be('default');
      // default values are persisted
      expect(config.get('obscureProperty')).to.be('default');
    });

    it('throws on unknown properties that don\'t have a value yet.', function () {
      const msg = 'Unexpected `config.get("throwableProperty")` call on unrecognized configuration setting';
      expect(config.get).withArgs('throwableProperty').to.throwException(msg);
    });
  });

  describe('#set', function () {
    it('stores a value in the config val set', function () {
      const original = config.get('dateFormat');
      config.set('dateFormat', 'notaformat');
      expect(config.get('dateFormat')).to.be('notaformat');
      config.set('dateFormat', original);
    });

    it('stores a value in a previously unknown config key', function () {
      expect(config.set).withArgs('unrecognizedProperty', 'somevalue').to.not.throwException();
      expect(config.get('unrecognizedProperty')).to.be('somevalue');
    });
  });

  describe('#$bind', function () {

    it('binds a config key to a $scope property', function () {
      const dateFormat = config.get('dateFormat');
      config.bindToScope($scope, 'dateFormat');
      expect($scope).to.have.property('dateFormat', dateFormat);
    });

    it('alows overriding the property name', function () {
      const dateFormat = config.get('dateFormat');
      config.bindToScope($scope, 'dateFormat', 'defaultDateFormat');
      expect($scope).to.not.have.property('dateFormat');
      expect($scope).to.have.property('defaultDateFormat', dateFormat);
    });

    it('keeps the property up to date', function () {
      const original = config.get('dateFormat');
      const newDateFormat = original + ' NEW NEW NEW!';
      config.bindToScope($scope, 'dateFormat');

      expect($scope).to.have.property('dateFormat', original);
      config.set('dateFormat', newDateFormat);
      expect($scope).to.have.property('dateFormat', newDateFormat);
      config.set('dateFormat', original);

    });

  });

});
Exemple #25
0
const init = function (index, type, id) {

  ngMock.module('kibana');

  // Stub services
  ngMock.module(function ($provide) {
    $provide.service('$route', function (Private) {
      this.current = {
        locals: {
          indexPattern: Private(FixturesStubbedLogstashIndexPatternProvider)
        },
        params: {
          index: index || 'myIndex',
          type: type || 'myType',
          id: id || 'myId'
        }
      };
    });

    $provide.service('es', function (Private, $q) {
      this.search = function (config) {
        const deferred = $q.defer();

        switch (config.index) {
          case 'goodSearch':
            deferred.resolve({
              hits: {
                total: 1,
                hits: [{
                  _source: {
                    foo: true
                  }
                }]
              }
            });
            break;
          case 'badSearch':
            deferred.resolve({
              hits: {
                total: 0,
                hits: []
              }
            });
            break;
          case 'missingIndex':
            deferred.reject({status: 404});
            break;
          case 'badRequest':
            deferred.reject({status: 500});
            break;
        }

        return deferred.promise;
      };
    });
  });

  // Create the scope
  ngMock.inject(function ($rootScope, $controller, _timefilter_) {
    $scope = $rootScope.$new();
    timefilter = _timefilter_;

    createController = function () {
      return $controller('doc', {
        '$scope': $scope
      });
    };
  });

  createController();
};
Exemple #26
0
describe('index pattern', function () {
  NoDigestPromises.activateForSuite();

  let IndexPattern;
  let mapper;
  let mappingSetup;
  let mockLogstashFields;
  let DocSource;
  let docSourceResponse;
  const indexPatternId = 'test-pattern';
  let indexPattern;
  let calculateIndices;
  let intervals;

  beforeEach(ngMock.module('kibana'));
  beforeEach(ngMock.inject(function (Private) {
    mockLogstashFields = Private(FixturesLogstashFieldsProvider);
    docSourceResponse = Private(FixturesStubbedDocSourceResponseProvider);

    DocSource = Private(AdminDocSourceProvider);
    sinon.stub(DocSource.prototype, 'doIndex');
    sinon.stub(DocSource.prototype, 'fetch');
    mapper = stubMapper(Private, mockLogstashFields);

    // stub mappingSetup
    mappingSetup = Private(UtilsMappingSetupProvider);
    sinon.stub(mappingSetup, 'isDefined', function () {
      return Promise.resolve(true);
    });

    // stub calculateIndices
    calculateIndices = sinon.spy(function () {
      return Promise.resolve([
        { index: 'foo', max: Infinity, min: -Infinity },
        { index: 'bar', max: Infinity, min: -Infinity }
      ]);
    });
    Private.stub(IndexPatternsCalculateIndicesProvider, calculateIndices);

    // spy on intervals
    intervals = Private(IndexPatternsIntervalsProvider);
    sinon.stub(intervals, 'toIndexList').returns([
      { index: 'foo', max: Infinity, min: -Infinity },
      { index: 'bar', max: Infinity, min: -Infinity }
    ]);

    IndexPattern = Private(IndexPatternProvider);
  }));

  // create an indexPattern instance for each test
  beforeEach(function () {
    return create(indexPatternId).then(function (pattern) {
      indexPattern = pattern;
    });
  });

  // helper function to create index patterns
  function create(id, payload) {
    const indexPattern = new IndexPattern(id);
    DocSource.prototype.doIndex.returns(Promise.resolve(id));
    payload = _.defaults(payload || {}, docSourceResponse(id));
    setDocsourcePayload(payload);
    return indexPattern.init();
  }

  function setDocsourcePayload(payload) {
    DocSource.prototype.fetch.returns(Promise.resolve(payload));
  }

  describe('api', function () {
    it('should have expected properties', function () {
      return create('test-pattern').then(function (indexPattern) {
        // methods
        expect(indexPattern).to.have.property('refreshFields');
        expect(indexPattern).to.have.property('popularizeField');
        expect(indexPattern).to.have.property('getScriptedFields');
        expect(indexPattern).to.have.property('getNonScriptedFields');
        expect(indexPattern).to.have.property('getInterval');
        expect(indexPattern).to.have.property('addScriptedField');
        expect(indexPattern).to.have.property('removeScriptedField');
        expect(indexPattern).to.have.property('toString');
        expect(indexPattern).to.have.property('toJSON');
        expect(indexPattern).to.have.property('save');

        // properties
        expect(indexPattern).to.have.property('fields');
      });
    });
  });

  describe('init', function () {
    it('should append the found fields', function () {
      expect(DocSource.prototype.fetch.callCount).to.be(1);
      expect(indexPattern.fields).to.have.length(mockLogstashFields.length);
      expect(indexPattern.fields).to.be.an(IndexedArray);
    });
  });

  describe('fields', function () {
    it('should have expected properties on fields', function () {
      expect(indexPattern.fields[0]).to.have.property('displayName');
      expect(indexPattern.fields[0]).to.have.property('filterable');
      expect(indexPattern.fields[0]).to.have.property('format');
      expect(indexPattern.fields[0]).to.have.property('sortable');
      expect(indexPattern.fields[0]).to.have.property('scripted');
    });
  });

  describe('getScriptedFields', function () {
    it('should return all scripted fields', function () {
      const scriptedNames = _(mockLogstashFields).where({ scripted: true }).pluck('name').value();
      const respNames = _.pluck(indexPattern.getScriptedFields(), 'name');
      expect(respNames).to.eql(scriptedNames);
    });
  });

  describe('getNonScriptedFields', function () {
    it('should return all non-scripted fields', function () {
      const notScriptedNames = _(mockLogstashFields).where({ scripted: false }).pluck('name').value();
      const respNames = _.pluck(indexPattern.getNonScriptedFields(), 'name');
      expect(respNames).to.eql(notScriptedNames);
    });

  });

  describe('refresh fields', function () {
    // override the default indexPattern, with a truncated field list
    const indexPatternId = 'test-pattern';
    let indexPattern;
    let customFields;

    beforeEach(function () {
      customFields = [{
        analyzed: true,
        count: 30,
        filterable: true,
        indexed: true,
        name: 'foo',
        scripted: false,
        sortable: true,
        type: 'number',
        aggregatable: true,
        searchable: false
      },
      {
        name: 'script number',
        type: 'number',
        scripted: true,
        script: '1234',
        lang: 'expression'
      }];

      return create(indexPatternId, {
        _source: {
          customFormats: '{}',
          fields: JSON.stringify(customFields)
        }
      }).then(function (pattern) {
        indexPattern = pattern;
      });
    });

    it('should fetch fields from the doc source', function () {
      // ensure that we don't have all the fields
      expect(customFields.length).to.not.equal(mockLogstashFields.length);
      expect(indexPattern.fields).to.have.length(customFields.length);

      // ensure that all fields will be included in the returned docSource
      setDocsourcePayload(docSourceResponse(indexPatternId));

      return Promise.all([
        // read fields from elasticsearch
        mapper.getFieldsForIndexPattern(),

        // tell the index pattern to do the same
        indexPattern.refreshFields(),
      ])
      .then(function (data) {
        const expected = data[0]; // just the fields in the index
        const fields = indexPattern.getNonScriptedFields(); // get all but scripted fields

        expect(_.pluck(fields, 'name')).to.eql(_.pluck(expected, 'name'));
      });
    });

    it('should preserve the scripted fields', function () {
      // ensure that all fields will be included in the returned docSource
      setDocsourcePayload(docSourceResponse(indexPatternId));

      // add spy to indexPattern.getScriptedFields
      const scriptedFieldsSpy = sinon.spy(indexPattern, 'getScriptedFields');

      // refresh fields, which will fetch
      return indexPattern.refreshFields().then(function () {
        // called to append scripted fields to the response from mapper.getFieldsForIndexPattern
        expect(scriptedFieldsSpy.callCount).to.equal(1);

        const expected = _.filter(indexPattern.fields, { scripted: true });
        expect(_.pluck(expected, 'name')).to.eql(['script number']);
      });
    });
  });

  describe('add and remove scripted fields', function () {
    it('should append the scripted field', function () {
      // keep a copy of the current scripted field count
      const saveSpy = sinon.spy(indexPattern, 'save');
      const oldCount = indexPattern.getScriptedFields().length;

      // add a new scripted field
      const scriptedField = {
        name: 'new scripted field',
        script: 'false',
        type: 'boolean'
      };
      indexPattern.addScriptedField(scriptedField.name, scriptedField.script, scriptedField.type);
      const scriptedFields = indexPattern.getScriptedFields();
      expect(saveSpy.callCount).to.equal(1);
      expect(scriptedFields).to.have.length(oldCount + 1);
      expect(indexPattern.fields.byName[scriptedField.name].name).to.equal(scriptedField.name);
    });

    it('should remove scripted field, by name', function () {
      const saveSpy = sinon.spy(indexPattern, 'save');
      const scriptedFields = indexPattern.getScriptedFields();
      const oldCount = scriptedFields.length;
      const scriptedField = _.last(scriptedFields);

      indexPattern.removeScriptedField(scriptedField.name);

      expect(saveSpy.callCount).to.equal(1);
      expect(indexPattern.getScriptedFields().length).to.equal(oldCount - 1);
      expect(indexPattern.fields.byName[scriptedField.name]).to.equal(undefined);
    });

    it('should not allow duplicate names', function () {
      const scriptedFields = indexPattern.getScriptedFields();
      const scriptedField = _.last(scriptedFields);
      expect(function () {
        indexPattern.addScriptedField(scriptedField.name, '\'new script\'', 'string');
      }).to.throwError(function (e) {
        expect(e).to.be.a(DuplicateField);
      });
    });
  });

  describe('popularizeField', function () {
    it('should increment the poplarity count by default', function () {
      const saveSpy = sinon.stub(indexPattern, 'save');
      indexPattern.fields.forEach(function (field, i) {
        const oldCount = field.count;

        indexPattern.popularizeField(field.name);

        expect(saveSpy.callCount).to.equal(i + 1);
        expect(field.count).to.equal(oldCount + 1);
      });
    });

    it('should increment the poplarity count', function () {
      const saveSpy = sinon.stub(indexPattern, 'save');
      indexPattern.fields.forEach(function (field, i) {
        const oldCount = field.count;
        const incrementAmount = 4;

        indexPattern.popularizeField(field.name, incrementAmount);

        expect(saveSpy.callCount).to.equal(i + 1);
        expect(field.count).to.equal(oldCount + incrementAmount);
      });
    });

    it('should decrement the poplarity count', function () {
      indexPattern.fields.forEach(function (field) {
        const oldCount = field.count;
        const incrementAmount = 4;
        const decrementAmount = -2;

        indexPattern.popularizeField(field.name, incrementAmount);
        indexPattern.popularizeField(field.name, decrementAmount);

        expect(field.count).to.equal(oldCount + incrementAmount + decrementAmount);
      });
    });

    it('should not go below 0', function () {
      indexPattern.fields.forEach(function (field) {
        const decrementAmount = -Number.MAX_VALUE;
        indexPattern.popularizeField(field.name, decrementAmount);
        expect(field.count).to.equal(0);
      });
    });
  });

  describe('#toDetailedIndexList', function () {
    describe('when index pattern is an interval', function () {
      let interval;
      beforeEach(function () {
        interval = 'result:getInterval';
        sinon.stub(indexPattern, 'getInterval').returns(interval);
      });

      it('invokes interval toDetailedIndexList with given start/stop times', async function () {
        await indexPattern.toDetailedIndexList(1, 2);
        const id = indexPattern.id;
        expect(intervals.toIndexList.calledWith(id, interval, 1, 2)).to.be(true);
      });
      it('is fulfilled by the result of interval toDetailedIndexList', async function () {
        const indexList = await indexPattern.toDetailedIndexList();
        expect(indexList[0].index).to.equal('foo');
        expect(indexList[1].index).to.equal('bar');
      });

      describe('with sort order', function () {
        it('passes the sort order to the intervals module', function () {
          return indexPattern.toDetailedIndexList(1, 2, 'SORT_DIRECTION')
          .then(function () {
            expect(intervals.toIndexList.callCount).to.be(1);
            expect(intervals.toIndexList.getCall(0).args[4]).to.be('SORT_DIRECTION');
          });
        });
      });
    });

    describe('when index pattern is a time-base wildcard', function () {
      beforeEach(function () {
        sinon.stub(indexPattern, 'getInterval').returns(false);
        sinon.stub(indexPattern, 'hasTimeField').returns(true);
        sinon.stub(indexPattern, 'isWildcard').returns(true);
      });

      it('invokes calculateIndices with given start/stop times and sortOrder', async function () {
        await indexPattern.toDetailedIndexList(1, 2, 'sortOrder');
        const id = indexPattern.id;
        const field = indexPattern.timeFieldName;
        expect(calculateIndices.calledWith(id, field, 1, 2, 'sortOrder')).to.be(true);
      });

      it('is fulfilled by the result of calculateIndices', async function () {
        const indexList = await indexPattern.toDetailedIndexList();
        expect(indexList[0].index).to.equal('foo');
        expect(indexList[1].index).to.equal('bar');
      });
    });

    describe('when index pattern is a time-base wildcard that is configured not to expand', function () {
      beforeEach(function () {
        sinon.stub(indexPattern, 'getInterval').returns(false);
        sinon.stub(indexPattern, 'hasTimeField').returns(true);
        sinon.stub(indexPattern, 'isWildcard').returns(true);
        sinon.stub(indexPattern, 'canExpandIndices').returns(false);
      });

      it('is fulfilled by id', async function () {
        const indexList = await indexPattern.toDetailedIndexList();
        expect(indexList.index).to.equal(indexPattern.id);
      });
    });

    describe('when index pattern is neither an interval nor a time-based wildcard', function () {
      beforeEach(function () {
        sinon.stub(indexPattern, 'getInterval').returns(false);
      });

      it('is fulfilled by id', async function () {
        const indexList = await indexPattern.toDetailedIndexList();
        expect(indexList.index).to.equal(indexPattern.id);
      });
    });
  });

  describe('#toIndexList', function () {
    describe('when index pattern is an interval', function () {

      let interval;
      beforeEach(function () {
        interval = 'result:getInterval';
        sinon.stub(indexPattern, 'getInterval').returns(interval);
      });

      it('invokes interval toIndexList with given start/stop times', async function () {
        await indexPattern.toIndexList(1, 2);
        const id = indexPattern.id;
        expect(intervals.toIndexList.calledWith(id, interval, 1, 2)).to.be(true);
      });
      it('is fulfilled by the result of interval toIndexList', async function () {
        const indexList = await indexPattern.toIndexList();
        expect(indexList[0]).to.equal('foo');
        expect(indexList[1]).to.equal('bar');
      });

      describe('with sort order', function () {
        it('passes the sort order to the intervals module', function () {
          return indexPattern.toIndexList(1, 2, 'SORT_DIRECTION')
          .then(function () {
            expect(intervals.toIndexList.callCount).to.be(1);
            expect(intervals.toIndexList.getCall(0).args[4]).to.be('SORT_DIRECTION');
          });
        });
      });
    });

    describe('when index pattern is a time-base wildcard', function () {
      beforeEach(function () {
        sinon.stub(indexPattern, 'getInterval').returns(false);
        sinon.stub(indexPattern, 'hasTimeField').returns(true);
        sinon.stub(indexPattern, 'isWildcard').returns(true);
      });

      it('invokes calculateIndices with given start/stop times and sortOrder', async function () {
        await indexPattern.toIndexList(1, 2, 'sortOrder');
        const id = indexPattern.id;
        const field = indexPattern.timeFieldName;
        expect(calculateIndices.calledWith(id, field, 1, 2, 'sortOrder')).to.be(true);
      });

      it('is fulfilled by the result of calculateIndices', async function () {
        const indexList = await indexPattern.toIndexList();
        expect(indexList[0]).to.equal('foo');
        expect(indexList[1]).to.equal('bar');
      });
    });

    describe('when index pattern is a time-base wildcard that is configured not to expand', function () {
      beforeEach(function () {
        sinon.stub(indexPattern, 'getInterval').returns(false);
        sinon.stub(indexPattern, 'hasTimeField').returns(true);
        sinon.stub(indexPattern, 'isWildcard').returns(true);
        sinon.stub(indexPattern, 'canExpandIndices').returns(false);
      });

      it('is fulfilled by id', async function () {
        const indexList = await indexPattern.toIndexList();
        expect(indexList).to.equal(indexPattern.id);
      });
    });

    describe('when index pattern is neither an interval nor a time-based wildcard', function () {
      beforeEach(function () {
        sinon.stub(indexPattern, 'getInterval').returns(false);
      });

      it('is fulfilled by id', async function () {
        const indexList = await indexPattern.toIndexList();
        expect(indexList).to.equal(indexPattern.id);
      });
    });
  });

  describe('#canExpandIndices()', function () {
    it('returns true if notExpandable is false', function () {
      indexPattern.notExpandable = false;
      expect(indexPattern.canExpandIndices()).to.be(true);
    });
    it('returns true if notExpandable is not defined', function () {
      delete indexPattern.notExpandable;
      expect(indexPattern.canExpandIndices()).to.be(true);
    });
    it('returns false if notExpandable is true', function () {
      indexPattern.notExpandable = true;
      expect(indexPattern.canExpandIndices()).to.be(false);
    });
  });

  describe('#hasTimeField()', function () {
    beforeEach(function () {
      // for the sake of these tests, it doesn't much matter what type of field
      // this is so long as it exists
      indexPattern.timeFieldName = 'bytes';
    });
    it('returns false if no time field', function () {
      delete indexPattern.timeFieldName;
      expect(indexPattern.hasTimeField()).to.be(false);
    });
    it('returns false if time field does not actually exist in fields', function () {
      indexPattern.timeFieldName = 'does not exist';
      expect(indexPattern.hasTimeField()).to.be(false);
    });
    it('returns true if valid time field is configured', function () {
      expect(indexPattern.hasTimeField()).to.be(true);
    });
  });

  describe('#isWildcard()', function () {
    it('returns true if id has an *', function () {
      indexPattern.id = 'foo*';
      expect(indexPattern.isWildcard()).to.be(true);
    });
    it('returns false if id has no *', function () {
      indexPattern.id = 'foo';
      expect(indexPattern.isWildcard()).to.be(false);
    });
  });
});
Exemple #27
0
describe('Courier DocFetchRequest class', function () {
  let storage;
  let source;
  let defer;
  let req;

  let setVersion;

  beforeEach(ngMock.module('kibana'));
  beforeEach(ngMock.inject(function (Private, Promise, $injector) {
    const DocSource = Private(DocSourceProvider);
    const DocFetchRequest = Private(DocRequestProvider);

    storage =
    $injector.get('localStorage').store =
    $injector.get('sessionStorage').store = {
      getItem: sinon.stub(),
      setItem: sinon.stub(),
      removeItem: sinon.stub(),
      clear: sinon.stub()
    };

    source = new DocSource({})
    .set('index', 'doc-index')
    .set('type', 'doc-type')
    .set('id', 'doc-id');

    defer = Promise.defer();

    req = new DocFetchRequest(source, defer);

    /**
     * Setup the version numbers for tests. There are two versions for the
     * purposes of these tests.
     *
     * @param {number} mine - the version that the DocSource most
     *                      recently received from elasticsearch.
     * @param {number} theirs - the version that other DocSources have
     *                        received from elasticsearfch.
     */
    setVersion = function (mine, theirs) {
      source._version = mine;
      storage.getItem.withArgs(source._versionKey()).returns(theirs);
    };
  }));

  describe('#canStart', function () {
    it('can if the doc is unknown', function () {
      setVersion(undefined, undefined);

      expect(req.canStart()).to.be(true);
    });

    it('cannot if the doc is unknown but the request is already in progress', function () {
      setVersion(undefined, undefined);
      req.start();

      expect(req.canStart()).to.be(false);
    });

    it('can if the doc is out of date', function () {
      setVersion(1, 2);

      expect(req.canStart()).to.be(true);
    });

    it('can if the doc is out of date and the request is in progress', function () {
      setVersion(1, 2);
      req.start();

      expect(req.canStart()).to.be(true);
    });

    it('cannot if the doc is up to date', function () {
      setVersion(2, 2);

      expect(req.canStart()).to.be(false);
    });

    it('can if the doc is overdated', function () {
      setVersion(5, 2);

      expect(req.canStart()).to.be(true);
    });

    it('can if shared version is cleared', function () {
      setVersion(10, undefined);

      expect(req.canStart()).to.be(true);
    });

    it('can if everyone else has a doc', function () {
      setVersion(undefined, 10);

      expect(req.canStart()).to.be(true);
    });
  });
});
Exemple #28
0
  describe('date_histogram', function () {
    let vis;
    let agg;
    let field;
    let filter;
    let bucketKey;
    let bucketStart;
    let intervalOptions;

    let init;

    beforeEach(ngMock.module('kibana', function ($provide) {
      $provide.constant('kbnDefaultAppId', '');
    }));
    beforeEach(ngMock.inject(function (Private) {
      const Vis = Private(VisProvider);
      const indexPattern = Private(FixturesStubbedLogstashIndexPatternProvider);
      const createFilter = Private(AggTypesBucketsCreateFilterDateHistogramProvider);
      intervalOptions = Private(AggTypesBucketsIntervalOptionsProvider);

      init = function (interval, duration) {
        interval = interval || 'auto';
        if (interval === 'custom') interval = agg.params.customInterval;
        duration = duration || moment.duration(15, 'minutes');
        field = _.sample(_.reject(indexPattern.fields.byType.date, 'scripted'));
        vis = new Vis(indexPattern, {
          type: 'histogram',
          aggs: [
            {
              type: 'date_histogram',
              schema: 'segment',
              params: { field: field.name, interval: interval, customInterval: '5d' }
            }
          ]
        });

        agg = vis.aggs[0];
        bucketKey = _.sample(aggResp.aggregations['1'].buckets).key;
        bucketStart = moment(bucketKey);

        const timePad = moment.duration(duration / 2);
        agg.buckets.setBounds({
          min: bucketStart.clone().subtract(timePad),
          max: bucketStart.clone().add(timePad),
        });
        agg.buckets.setInterval(interval);

        filter = createFilter(agg, bucketKey);
      };
    }));

    it('creates a valid range filter', function () {
      init();

      expect(filter).to.have.property('range');
      expect(filter.range).to.have.property(field.name);

      const fieldParams = filter.range[field.name];
      expect(fieldParams).to.have.property('gte');
      expect(fieldParams.gte).to.be.a('number');

      expect(fieldParams).to.have.property('lt');
      expect(fieldParams.lt).to.be.a('number');

      expect(fieldParams).to.have.property('format');
      expect(fieldParams.format).to.be('epoch_millis');

      expect(fieldParams.gte).to.be.lessThan(fieldParams.lt);

      expect(filter).to.have.property('meta');
      expect(filter.meta).to.have.property('index', vis.indexPattern.id);
    });


    it('extends the filter edge to 1ms before the next bucket for all interval options', function () {
      intervalOptions.forEach(function (option) {
        let duration;
        if (option.val !== 'custom' && moment(1, option.val).isValid()) {
          duration = moment.duration(10, option.val);

          if (+duration < 10) {
            throw new Error('unable to create interval for ' + option.val);
          }
        }

        init(option.val, duration);

        const interval = agg.buckets.getInterval();
        const params = filter.range[field.name];

        expect(params.gte).to.be(+bucketStart);
        expect(params.lt).to.be(+bucketStart.clone().add(interval));
      });
    });
  });
Exemple #29
0
describe('AggTableGroup Directive', function () {

  let $rootScope;
  let $compile;
  let tabifyAggResponse;
  let Vis;
  let indexPattern;

  beforeEach(ngMock.module('kibana'));
  beforeEach(ngMock.inject(function ($injector, Private) {
    tabifyAggResponse = Private(AggResponseTabifyTabifyProvider);
    indexPattern = Private(FixturesStubbedLogstashIndexPatternProvider);
    Vis = Private(VisProvider);

    $rootScope = $injector.get('$rootScope');
    $compile = $injector.get('$compile');
  }));

  let $scope;
  beforeEach(function () {
    $scope = $rootScope.$new();
  });
  afterEach(function () {
    $scope.$destroy();
  });


  it('renders a simple split response properly', function () {
    const vis = new Vis(indexPattern, 'table');
    $scope.group = tabifyAggResponse(vis, fixtures.metricOnly);
    $scope.sort = {
      columnIndex: null,
      direction: null
    };
    const $el = $('<kbn-agg-table-group group="group"></kbn-agg-table-group>');

    $compile($el)($scope);
    $scope.$digest();

    // should create one sub-tbale
    expect($el.find('kbn-agg-table').size()).to.be(1);
  });

  it('renders nothing if the table list is empty', function () {
    const $el = $('<kbn-agg-table-group group="group"></kbn-agg-table-group>');

    $scope.group = {
      tables: []
    };

    $compile($el)($scope);
    $scope.$digest();

    const $subTables = $el.find('kbn-agg-table');
    expect($subTables.size()).to.be(0);
  });

  it('renders a complex response properly', function () {
    const vis = new Vis(indexPattern, {
      type: 'pie',
      aggs: [
        { type: 'avg', schema: 'metric', params: { field: 'bytes' } },
        { type: 'terms', schema: 'split', params: { field: 'extension' } },
        { type: 'terms', schema: 'segment', params: { field: 'geo.src' } },
        { type: 'terms', schema: 'segment', params: { field: 'machine.os' } }
      ]
    });
    vis.aggs.forEach(function (agg, i) {
      agg.id = 'agg_' + (i + 1);
    });

    const group = $scope.group = tabifyAggResponse(vis, fixtures.threeTermBuckets);
    const $el = $('<kbn-agg-table-group group="group"></kbn-agg-table-group>');
    $compile($el)($scope);
    $scope.$digest();

    const $subTables = $el.find('kbn-agg-table');
    expect($subTables.size()).to.be(3);

    const $subTableHeaders = $el.find('.agg-table-group-header');
    expect($subTableHeaders.size()).to.be(3);

    $subTableHeaders.each(function (i) {
      expect($(this).text()).to.be(group.tables[i].title);
    });
  });
});
Exemple #30
0
describe('Events', function () {
  require('test_utils/no_digest_promises').activateForSuite();

  let Events;
  let Promise;
  let eventsInstance;

  beforeEach(ngMock.module('kibana'));
  beforeEach(ngMock.inject(function ($injector, Private) {
    Promise = $injector.get('Promise');
    Events = Private(EventsProvider);
    eventsInstance = new Events();
  }));

  it('should handle on events', function () {
    const obj = new Events();
    const prom = obj.on('test', function (message) {
      expect(message).to.equal('Hello World');
    });

    obj.emit('test', 'Hello World');

    return prom;
  });

  it('should work with inherited objects', function () {
    createLegacyClass(MyEventedObject).inherits(Events);
    function MyEventedObject() {
      MyEventedObject.Super.call(this);
    }
    const obj = new MyEventedObject();

    const prom = obj.on('test', function (message) {
      expect(message).to.equal('Hello World');
    });

    obj.emit('test', 'Hello World');

    return prom;
  });

  it('should clear events when off is called', function () {
    const obj = new Events();
    obj.on('test', _.noop);
    expect(obj._listeners).to.have.property('test');
    expect(obj._listeners.test).to.have.length(1);
    obj.off();
    expect(obj._listeners).to.not.have.property('test');
  });

  it('should clear a specific handler when off is called for an event', function () {
    const obj = new Events();
    const handler1 = sinon.stub();
    const handler2 = sinon.stub();
    obj.on('test', handler1);
    obj.on('test', handler2);
    expect(obj._listeners).to.have.property('test');
    obj.off('test', handler1);

    return obj.emit('test', 'Hello World')
      .then(function () {
        sinon.assert.calledOnce(handler2);
        sinon.assert.notCalled(handler1);
      });
  });

  it('should clear a all handlers when off is called for an event', function () {
    const obj = new Events();
    const handler1 = sinon.stub();
    obj.on('test', handler1);
    expect(obj._listeners).to.have.property('test');
    obj.off('test');
    expect(obj._listeners).to.not.have.property('test');

    return obj.emit('test', 'Hello World')
      .then(function () {
        sinon.assert.notCalled(handler1);
      });
  });

  it('should handle multiple identical emits in the same tick', function () {
    const obj = new Events();
    const handler1 = sinon.stub();

    obj.on('test', handler1);
    const emits = [
      obj.emit('test', 'one'),
      obj.emit('test', 'two'),
      obj.emit('test', 'three')
    ];

    return Promise
      .all(emits)
      .then(function () {
        expect(handler1.callCount).to.be(emits.length);
        expect(handler1.getCall(0).calledWith('one')).to.be(true);
        expect(handler1.getCall(1).calledWith('two')).to.be(true);
        expect(handler1.getCall(2).calledWith('three')).to.be(true);
      });
  });

  it('should handle emits from the handler', function () {
    const obj = new Events();
    const secondEmit = Promise.defer();
    const handler1 = sinon.spy(function () {
      if (handler1.calledTwice) {
        return;
      }
      obj.emit('test').then(_.bindKey(secondEmit, 'resolve'));
    });

    obj.on('test', handler1);

    return Promise
      .all([
        obj.emit('test'),
        secondEmit.promise
      ])
      .then(function () {
        expect(handler1.callCount).to.be(2);
      });
  });

  it('should only emit to handlers registered before emit is called', function () {
    const obj = new Events();
    const handler1 = sinon.stub();
    const handler2 = sinon.stub();

    obj.on('test', handler1);
    const emits = [
      obj.emit('test', 'one'),
      obj.emit('test', 'two'),
      obj.emit('test', 'three')
    ];


    return Promise.all(emits).then(function () {
      expect(handler1.callCount).to.be(emits.length);

      obj.on('test', handler2);

      const emits2 = [
        obj.emit('test', 'four'),
        obj.emit('test', 'five'),
        obj.emit('test', 'six')
      ];

      return Promise.all(emits2)
        .then(function () {
          expect(handler1.callCount).to.be(emits.length + emits2.length);
          expect(handler2.callCount).to.be(emits2.length);
        });
    });
  });

  it('should pass multiple arguments from the emitter', function () {
    const obj = new Events();
    const handler = sinon.stub();
    const payload = [
      'one',
      { hello: 'tests' },
      null
    ];

    obj.on('test', handler);

    return obj.emit('test', payload[0], payload[1], payload[2])
      .then(function () {
        expect(handler.callCount).to.be(1);
        expect(handler.calledWithExactly(payload[0], payload[1], payload[2])).to.be(true);
      });
  });

  it('should preserve the scope of the handler', function () {
    const obj = new Events();
    const expected = 'some value';
    let testValue;

    function handler() {
      testValue = this.getVal();
    }
    handler.getVal = _.constant(expected);

    obj.on('test', handler);
    return obj.emit('test')
      .then(function () {
        expect(testValue).to.equal(expected);
      });
  });

  it('should always emit in the same order', function () {
    const handler = sinon.stub();

    const obj = new Events();
    obj.on('block', _.partial(handler, 'block'));
    obj.on('last', _.partial(handler, 'last'));

    return Promise
      .all([
        obj.emit('block'),
        obj.emit('block'),
        obj.emit('block'),
        obj.emit('block'),
        obj.emit('block'),
        obj.emit('block'),
        obj.emit('block'),
        obj.emit('block'),
        obj.emit('block'),
        obj.emit('last')
      ])
      .then(function () {
        expect(handler.callCount).to.be(10);
        handler.args.forEach(function (args, i) {
          expect(args[0]).to.be(i < 9 ? 'block' : 'last');
        });
      });
  });

  it('calls emitted handlers asynchronously', (done) => {
    const listenerStub = sinon.stub();
    eventsInstance.on('test', listenerStub);
    eventsInstance.emit('test');
    sinon.assert.notCalled(listenerStub);

    setTimeout(() => {
      sinon.assert.calledOnce(listenerStub);
      done();
    }, 100);
  });

  it('calling off after an emit that has not yet triggered the handler, will not call the handler', (done) => {
    const listenerStub = sinon.stub();
    eventsInstance.on('test', listenerStub);
    eventsInstance.emit('test');
    // It's called asynchronously so it shouldn't be called yet.
    sinon.assert.notCalled(listenerStub);
    eventsInstance.off('test', listenerStub);

    setTimeout(() => {
      sinon.assert.notCalled(listenerStub);
      done();
    }, 100);
  });
});