+
No scripted fields defined
diff --git a/src/kibana/plugins/settings/sections/indices/_edit.js b/src/kibana/plugins/settings/sections/indices/_edit.js
index 0b74fcad21562..0b03000c944f2 100644
--- a/src/kibana/plugins/settings/sections/indices/_edit.js
+++ b/src/kibana/plugins/settings/sections/indices/_edit.js
@@ -1,5 +1,6 @@
define(function (require) {
var _ = require('lodash');
+ require('components/paginated_table/paginated_table');
require('routes')
.when('/settings/indices/:id', {
@@ -13,9 +14,13 @@ define(function (require) {
});
require('modules').get('apps/settings')
- .controller('settingsIndicesEdit', function ($scope, $location, $route, config, courier, Notifier, Private, AppState) {
+ .controller('settingsIndicesEdit', function ($scope, $location, $route, $compile,
+ config, courier, Notifier, Private, AppState) {
+
+ var rowScopes = []; // track row scopes, so they can be destroyed as needed
var notify = new Notifier();
var $state = $scope.state = new AppState();
+ var popularityHtml = require('text!plugins/settings/sections/indices/_popularity.html');
var refreshKibanaIndex = Private(require('plugins/settings/sections/indices/_refresh_kibana_index'));
$scope.indexPattern = $route.current.locals.indexPattern;
@@ -23,13 +28,50 @@ define(function (require) {
$scope.fieldTypes = Private(require('plugins/settings/sections/indices/_field_types'));
- $scope.table = {
- by: 'name',
- reverse: false,
- page: 0,
- max: 35
+ $scope.fieldColumns = [{
+ title: 'name'
+ }, {
+ title: 'type'
+ }, {
+ title: 'analyzed',
+ info: 'Analyzed fields may require extra memory to visualize'
+ }, {
+ title: 'indexed',
+ info: 'Fields that are not indexed are unavailable for search'
+ }, {
+ title: 'popularity',
+ info: 'A gauge of how often this field is used',
+ }];
+
+ $scope.showPopularityControls = function (field) {
+ $scope.popularityHoverState = (field) ? field : null;
};
+ $scope.$watchCollection('indexPattern.fields', function () {
+ _.invoke(rowScopes, '$destroy');
+
+ $scope.fieldRows = $scope.indexPattern.fields.map(function (field) {
+ var childScope = $scope.$new();
+ rowScopes.push(childScope);
+ childScope.field = field;
+
+ // update the active field via object comparison
+ if (_.isEqual(field, $scope.popularityHoverState)) {
+ $scope.showPopularityControls(field);
+ }
+
+ return [field.name, field.type, field.analyzed, field.indexed,
+ {
+ markup: $compile(popularityHtml)(childScope),
+ value: field.count
+ }
+ ];
+ });
+ });
+
+
+ $scope.perPage = 25;
+
$scope.changeTab = function (obj) {
$state.tab = obj.index;
$state.save();
@@ -65,24 +107,6 @@ define(function (require) {
config.set('defaultIndex', $scope.indexPattern.id);
};
- $scope.setFieldSort = function (by) {
- if ($scope.table.by === by) {
- $scope.table.reverse = !$scope.table.reverse;
- } else {
- $scope.table.by = by;
- }
- };
-
- $scope.sortClass = function (column) {
- if ($scope.table.by !== column) return;
- return $scope.table.reverse ? ['fa', 'fa-sort-asc'] : ['fa', 'fa-sort-desc'];
- };
-
- $scope.tablePages = function () {
- if (!$scope.indexPattern.fields) return 0;
- return Math.ceil($scope.indexPattern.fields.length / $scope.table.max);
- };
-
$scope.setIndexPatternsTimeField = function (field) {
if (field.type !== 'date') {
notify.error('That field is a ' + field.type + ' not a date.');
diff --git a/src/kibana/plugins/settings/sections/indices/_popularity.html b/src/kibana/plugins/settings/sections/indices/_popularity.html
new file mode 100644
index 0000000000000..a8d90dc6e9d51
--- /dev/null
+++ b/src/kibana/plugins/settings/sections/indices/_popularity.html
@@ -0,0 +1,9 @@
+
+ {{ field.count }}
+
+
+
+
+
'
\ No newline at end of file
diff --git a/src/kibana/plugins/settings/styles/main.less b/src/kibana/plugins/settings/styles/main.less
index da3e6567cd2ce..aa52bbe826d97 100644
--- a/src/kibana/plugins/settings/styles/main.less
+++ b/src/kibana/plugins/settings/styles/main.less
@@ -129,6 +129,13 @@ kbn-settings-objects-view {
}
}
+kbn-settings-indices .fields {
+ & th:first-child,
+ & td:first-child {
+ width: 35%;
+ }
+}
+
.kbn-settings-indices-create {
.time-and-pattern > div {}
}
diff --git a/test/unit/fixtures/fake_row.js b/test/unit/fixtures/fake_row.js
index dc04f07edcf57..0760b02bbd721 100644
--- a/test/unit/fixtures/fake_row.js
+++ b/test/unit/fixtures/fake_row.js
@@ -6,6 +6,7 @@ define(function (require) {
return function (id, mapping) {
var fake = {
_formatted: _.mapValues(mapping, function (f, c) { return c + '_formatted_' + id + longString; }),
+ _flattened: _.mapValues(mapping, function (f, c) { return c + '_flattened_' + id + longString; }),
_source: _.mapValues(mapping, function (f, c) { return c + '_original_' + id + longString; }),
_id: id,
_index: 'test',
diff --git a/test/unit/fixtures/stubbed_logstash_index_pattern.js b/test/unit/fixtures/stubbed_logstash_index_pattern.js
index 7f319154ed82f..da9aace183705 100644
--- a/test/unit/fixtures/stubbed_logstash_index_pattern.js
+++ b/test/unit/fixtures/stubbed_logstash_index_pattern.js
@@ -1,9 +1,10 @@
define(function (require) {
return function stubbedLogstashIndexPatternService(Private) {
var StubIndexPattern = Private(require('test_utils/stub_index_pattern'));
- var fieldFormats = Private(require('components/index_patterns/_field_formats'));
+ var flattenSearchResponse = require('components/index_patterns/_flatten_search_response');
+ var _ = require('lodash');
- return new StubIndexPattern('logstash-*', 'time', [
+ var indexPattern = new StubIndexPattern('logstash-*', 'time', [
{ name: 'bytes', displayName: 'bytes', type: 'number', indexed: true, analyzed: true, count: 10 },
{ name: 'ssl', displayName: 'ssl', type: 'boolean', indexed: true, analyzed: true, count: 20 },
{ name: '@timestamp', displayName: '@timestamp', type: 'date', indexed: true, analyzed: true, count: 30 },
@@ -19,5 +20,10 @@ define(function (require) {
{ name: '_type', displayName: '_type', type: 'string', indexed: true, analyzed: true, count: 0 },
{ name: 'custom_user_field', displayName: 'custom_user_field', type: 'conflict', indexed: false, analyzed: false, count: 0 }
]);
+
+ indexPattern.flattenSearchResponse = _.bind(flattenSearchResponse, indexPattern);
+
+ return indexPattern;
+
};
});
diff --git a/test/unit/specs/apps/discover/directives/field_calculator.js b/test/unit/specs/apps/discover/directives/field_calculator.js
index 8bb37cb4d2089..d01d3c3b5fb6b 100644
--- a/test/unit/specs/apps/discover/directives/field_calculator.js
+++ b/test/unit/specs/apps/discover/directives/field_calculator.js
@@ -87,7 +87,14 @@ define(function (require) {
});
describe('getFieldValues', function () {
- var hits = require('fixtures/real_hits.js');
+ var hits;
+
+ beforeEach(function () {
+ hits = _.each(require('fixtures/real_hits.js'), function (hit) {
+ hit._flattened = indexPattern.flattenSearchResponse(hit._source);
+ });
+ });
+
it('Should return an array of values for _source fields', function () {
var extensions = fieldCalculator.getFieldValues(hits, indexPattern.fields.byName.extension);
expect(extensions).to.be.an(Array);
diff --git a/test/unit/specs/apps/discover/directives/field_chooser.js b/test/unit/specs/apps/discover/directives/field_chooser.js
index 8431e5dbe2d2f..2f3a43806d46a 100644
--- a/test/unit/specs/apps/discover/directives/field_chooser.js
+++ b/test/unit/specs/apps/discover/directives/field_chooser.js
@@ -45,10 +45,14 @@ define(function (require) {
indexPattern = Private(require('fixtures/stubbed_logstash_index_pattern'));
});
+ var hits = _.each(require('fixtures/hits.js'), function (hit) {
+ hit._flattened = indexPattern.flattenSearchResponse(hit._source);
+ });
+
init($elem, {
fields: _.map(indexPattern.fields.raw, function (v, i) { return _.merge(v, {display: false, rowCount: i}); }),
toggle: sinon.spy(),
- data: require('fixtures/hits'),
+ data: hits,
filter: sinon.spy(),
indexPattern: indexPattern
});
diff --git a/test/unit/specs/components/agg_table/_table.js b/test/unit/specs/components/agg_table/_table.js
index 101b567fec07e..5b1d7dfd49c1c 100644
--- a/test/unit/specs/components/agg_table/_table.js
+++ b/test/unit/specs/components/agg_table/_table.js
@@ -103,158 +103,6 @@ define(function (require) {
});
});
- describe('aggTable.cycleSort()', function () {
- var vis;
- beforeEach(function () {
- vis = new Vis(indexPattern, {
- type: 'table',
- aggs: [
- { type: 'count', schema: 'metric' },
- {
- type: 'range',
- schema: 'bucket',
- params: {
- field: 'bytes',
- ranges: [
- { from: 0, to: 1000 },
- { from: 1000, to: 2000 }
- ]
- }
- }
- ]
- });
-
- vis.aggs.forEach(function (agg, i) {
- agg.id = 'agg_' + (i + 1);
- });
- });
-
- function checkAgainst(aggTable, $el, selector) {
- return function (asc, firstCol) {
- switch (asc) {
- case null:
- expect(aggTable.sort == null).to.be(true);
- break;
- case true:
- case false:
- expect(aggTable.sort).to.have.property('asc', asc);
- break;
- }
-
- var $leftCol = $el.find(selector || 'tr td:first-child');
- firstCol.forEach(function (val, i) {
- expect($leftCol.eq(i).text().trim()).to.be(val);
- });
- };
- }
-
- it('sorts by the column passed in', function () {
- $scope.table = tabifyAggResponse(vis, fixtures.oneRangeBucket, { canSplit: false });
- var $el = $compile('
')($scope);
- $scope.$digest();
-
- var sortCol = $scope.table.columns[0];
- var $tableScope = $el.isolateScope();
- var aggTable = $tableScope.aggTable;
- var check = checkAgainst(aggTable, $el);
-
- // default state
- check(null, [
- '0.0-1000.0',
- '1000.0-2000.0'
- ]);
-
- // enable accending
- aggTable.cycleSort(sortCol);
- $scope.$digest();
- check(true, [
- '0.0-1000.0',
- '1000.0-2000.0'
- ]);
-
- // enable descending
- aggTable.cycleSort(sortCol);
- $scope.$digest();
- check(false, [
- '1000.0-2000.0',
- '0.0-1000.0'
- ]);
-
- // disable sort
- aggTable.cycleSort(sortCol);
- $scope.$digest();
- check(null, [
- '0.0-1000.0',
- '1000.0-2000.0'
- ]);
- });
-
- it('sorts new tables by the previous sort rule', function () {
- $scope.table = tabifyAggResponse(vis, fixtures.oneRangeBucket, { canSplit: false });
- var $el = $compile('')($scope);
- $scope.$digest();
-
- var sortCol = $scope.table.columns[0];
- var $tableScope = $el.isolateScope();
- var aggTable = $tableScope.aggTable;
- var check = checkAgainst(aggTable, $el);
-
- // enable accending, then descending
- aggTable.cycleSort(sortCol);
- aggTable.cycleSort(sortCol);
- $scope.$digest();
- check(false, [
- '1000.0-2000.0',
- '0.0-1000.0'
- ]);
-
- var prevFormattedRows = $tableScope.formattedRows;
-
- // change the table and trigger the watchers
- $scope.table = tabifyAggResponse(vis, fixtures.oneRangeBucket, { canSplit: false });
- $scope.$digest();
-
- // prove that the rows were recreated
- expect($tableScope.formattedRows).to.not.be(prevFormattedRows);
-
- // check that the order is right
- check(false, [
- '1000.0-2000.0',
- '0.0-1000.0'
- ]);
- });
-
- it('sorts ascending when switching from another column', function () {
- $scope.table = tabifyAggResponse(vis, fixtures.oneRangeBucket, { canSplit: false });
- var $el = $compile('')($scope);
- $scope.$digest();
-
- var $tableScope = $el.isolateScope();
- var aggTable = $tableScope.aggTable;
-
- var rangeCol = $scope.table.columns[0];
- var countCol = $scope.table.columns[1];
- var checkRange = checkAgainst(aggTable, $el, 'tr td:first-child');
- var checkCount = checkAgainst(aggTable, $el, 'tr td:last-child');
-
- // sort count accending
- aggTable.cycleSort(countCol);
- $scope.$digest();
- checkCount(true, [
- '298',
- '606'
- ]);
-
- // switch to sorting range ascending
- aggTable.cycleSort(rangeCol);
- $scope.$digest();
- checkRange(true, [
- '0.0-1000.0',
- '1000.0-2000.0'
- ]);
- });
- });
-
describe('aggTable.toCsv()', function () {
it('escapes and formats the rows and columns properly', function () {
var $el = $compile('')($scope);
diff --git a/test/unit/specs/components/paginated_table/index.js b/test/unit/specs/components/paginated_table/index.js
new file mode 100644
index 0000000000000..dfeec7a7c460c
--- /dev/null
+++ b/test/unit/specs/components/paginated_table/index.js
@@ -0,0 +1,232 @@
+define(function (require) {
+ require('components/paginated_table/paginated_table');
+ var _ = require('lodash');
+ var faker = require('faker');
+ var sinon = require('sinon/sinon');
+
+ describe('paginated table', function () {
+ var $el;
+ var $rootScope;
+ var $compile;
+ var $scope;
+ var $elScope;
+ var $orderBy;
+ var defaultPerPage = 10;
+
+ var makeData = function (colCount, rowCount) {
+ var cols = faker.Lorem.words(colCount).map(function (word) {
+ return { title: word };
+ });
+ var rows = [];
+ _.times(rowCount, function () {
+ rows.push(faker.Lorem.words(colCount));
+ });
+
+ return {
+ columns: cols,
+ rows: rows
+ };
+ };
+
+ var renderTable = function (cols, rows, perPage) {
+ $scope.cols = cols || [];
+ $scope.rows = rows || [];
+ $scope.perPage = perPage || defaultPerPage;
+
+ $el = $compile('')($scope);
+
+ $scope.$digest();
+ };
+
+ beforeEach(function () {
+ module('kibana');
+
+ inject(function (_$rootScope_, _$compile_, $filter) {
+ $rootScope = _$rootScope_;
+ $compile = _$compile_;
+ $orderBy = $filter('orderBy');
+ });
+
+ $scope = $rootScope.$new();
+ });
+
+ afterEach(function () {
+ $scope.$destroy();
+ });
+
+ describe('rendering', function () {
+ it('should not display without rows', function () {
+ var cols = [{
+ title: 'test1'
+ }];
+ var rows = [];
+
+ renderTable(cols, rows);
+ expect($el.children().size()).to.be(0);
+ });
+
+ it('should render columns and rows', function () {
+ var data = makeData(2, 2);
+ var cols = data.columns;
+ var rows = data.rows;
+
+ renderTable(cols, rows);
+ expect($el.children().size()).to.be(1);
+ var tableRows = $el.find('tbody tr');
+ // should pad rows
+ expect(tableRows.size()).to.be(defaultPerPage);
+ // should contain the row data
+ expect(tableRows.eq(0).find('td').eq(0).text()).to.be(rows[0][0]);
+ expect(tableRows.eq(0).find('td').eq(1).text()).to.be(rows[0][1]);
+ expect(tableRows.eq(1).find('td').eq(0).text()).to.be(rows[1][0]);
+ expect(tableRows.eq(1).find('td').eq(1).text()).to.be(rows[1][1]);
+ });
+
+ it('should paginate rows', function () {
+ // note: paginate truncates pages, so don't make too many
+ var rowCount = _.random(16, 24);
+ var perPageCount = _.random(5, 8);
+ var data = makeData(3, rowCount);
+ var pageCount = Math.ceil(rowCount / perPageCount);
+
+ renderTable(data.columns, data.rows, perPageCount);
+ var tableRows = $el.find('tbody tr');
+ expect(tableRows.size()).to.be(perPageCount);
+ // add 2 for the first and last page links
+ expect($el.find('paginate-controls a').size()).to.be(pageCount + 2);
+ });
+ });
+
+ describe('sorting', function () {
+ var data;
+ var lastRowIndex;
+ var paginatedTable;
+
+ beforeEach(function () {
+ data = makeData(3, 3);
+ data.rows.push(['zzzz', 'zzzz', 'zzzz']);
+ data.rows.push(['aaaa', 'aaaa', 'aaaa']);
+
+ lastRowIndex = data.rows.length - 1;
+ renderTable(data.columns, data.rows);
+ paginatedTable = $el.isolateScope().paginatedTable;
+ });
+
+ afterEach(function () {
+ $scope.$destroy();
+ });
+
+ it('should not sort by default', function () {
+ var tableRows = $el.find('tbody tr');
+ expect(tableRows.eq(0).find('td').eq(0).text()).to.be(data.rows[0][0]);
+ expect(tableRows.eq(lastRowIndex).find('td').eq(0).text()).to.be('aaaa');
+ });
+
+ it('should sort ascending on first invocation', function () {
+ // sortColumn
+ paginatedTable.sortColumn(data.columns[0]);
+ $scope.$digest();
+ var tableRows = $el.find('tbody tr');
+ expect(tableRows.eq(0).find('td').eq(0).text()).to.be('aaaa');
+ expect(tableRows.eq(lastRowIndex).find('td').eq(0).text()).to.be('zzzz');
+ });
+
+ it('should sort desciending on second invocation', function () {
+ // sortColumn
+ paginatedTable.sortColumn(data.columns[0]);
+ paginatedTable.sortColumn(data.columns[0]);
+ $scope.$digest();
+ var tableRows = $el.find('tbody tr');
+ expect(tableRows.eq(0).find('td').eq(0).text()).to.be('zzzz');
+ expect(tableRows.eq(lastRowIndex).find('td').eq(0).text()).to.be('aaaa');
+ });
+
+ it('should clear sorting on third invocation', function () {
+ // sortColumn
+ paginatedTable.sortColumn(data.columns[0]);
+ paginatedTable.sortColumn(data.columns[0]);
+ paginatedTable.sortColumn(data.columns[0]);
+ $scope.$digest();
+ var tableRows = $el.find('tbody tr');
+ expect(tableRows.eq(0).find('td').eq(0).text()).to.be(data.rows[0][0]);
+ expect(tableRows.eq(lastRowIndex).find('td').eq(0).text()).to.be('aaaa');
+ });
+ });
+
+ describe('custom sorting', function () {
+ var data;
+ var paginatedTable;
+ var sortHandler;
+
+ beforeEach(function () {
+ sortHandler = sinon.spy();
+ data = makeData(3, 3);
+ $scope.cols = data.columns;
+ $scope.rows = data.rows;
+ $scope.perPage = defaultPerPage;
+ $scope.sortHandler = sortHandler;
+
+ $el = $compile('')($scope);
+
+ $scope.$digest();
+ paginatedTable = $el.isolateScope().paginatedTable;
+ });
+
+ it('should allow custom sorting handler', function () {
+ var columnIndex = 1;
+ paginatedTable.sortColumn(data.columns[columnIndex]);
+ $scope.$digest();
+ expect(sortHandler.callCount).to.be(1);
+ expect(sortHandler.getCall(0).args[0]).to.be(columnIndex);
+ });
+ });
+
+ describe('object rows', function () {
+ var cols;
+ var rows;
+ var paginatedTable;
+
+ beforeEach(function () {
+ cols = [{
+ title: 'object test'
+ }];
+ rows = [
+ ['aaaa'],
+ [{
+ markup: 'I am HTML in a row
',
+ value: 'zzzz'
+ }],
+ ['bbbb']
+ ];
+ renderTable(cols, rows);
+ paginatedTable = $el.isolateScope().paginatedTable;
+ });
+
+ it('should append object markup', function () {
+ var tableRows = $el.find('tbody tr');
+ expect(tableRows.eq(0).find('h1').size()).to.be(0);
+ expect(tableRows.eq(1).find('h1').size()).to.be(1);
+ expect(tableRows.eq(2).find('h1').size()).to.be(0);
+ });
+
+ it('should sort using object value', function () {
+ paginatedTable.sortColumn(cols[0]);
+ $scope.$digest();
+ var tableRows = $el.find('tbody tr');
+ expect(tableRows.eq(0).find('h1').size()).to.be(0);
+ expect(tableRows.eq(1).find('h1').size()).to.be(0);
+ // html row should be the last row
+ expect(tableRows.eq(2).find('h1').size()).to.be(1);
+
+ paginatedTable.sortColumn(cols[0]);
+ $scope.$digest();
+ tableRows = $el.find('tbody tr');
+ // html row should be the first row
+ expect(tableRows.eq(0).find('h1').size()).to.be(1);
+ expect(tableRows.eq(1).find('h1').size()).to.be(0);
+ expect(tableRows.eq(2).find('h1').size()).to.be(0);
+ });
+ });
+ });
+});
diff --git a/test/unit/specs/components/vis/vis.js b/test/unit/specs/components/vis/vis.js
new file mode 100644
index 0000000000000..88d33511e6de0
--- /dev/null
+++ b/test/unit/specs/components/vis/vis.js
@@ -0,0 +1,107 @@
+define(function (require) {
+ var _ = require('lodash');
+
+ var indexPattern;
+ var Vis;
+ var visTypes;
+
+ describe('Vis Class', function () {
+
+ var vis;
+ var stateFixture = {
+ type: 'pie',
+ aggs: [
+ { type: 'avg', schema: 'metric', params: { field: 'bytes' } },
+ { type: 'terms', schema: 'segment', params: { field: 'machine.os' }},
+ { type: 'terms', schema: 'segment', params: { field: 'geo.src' }}
+ ],
+ params: { isDonut: true },
+ listeners: { click: _.noop }
+ };
+
+ beforeEach(module('kibana'));
+ beforeEach(inject(function (Private) {
+ Vis = Private(require('components/vis/vis'));
+ indexPattern = Private(require('fixtures/stubbed_logstash_index_pattern'));
+ visTypes = Private(require('registry/vis_types'));
+ }));
+
+ beforeEach(function () {
+ vis = new Vis(indexPattern, stateFixture);
+ });
+
+ var verifyVis = function (vis) {
+ expect(vis).to.have.property('aggs');
+ expect(vis.aggs).to.have.length(3);
+
+ expect(vis).to.have.property('type');
+ expect(vis.type).to.eql(visTypes.byName['pie']);
+
+ expect(vis).to.have.property('listeners');
+ expect(vis.listeners).to.have.property('click');
+ expect(vis.listeners.click).to.eql(_.noop);
+
+ expect(vis).to.have.property('params');
+ expect(vis.params).to.have.property('isDonut', true);
+ expect(vis).to.have.property('indexPattern', indexPattern);
+ };
+
+ describe('initialization', function () {
+ it('should set the state', function () {
+ verifyVis(vis);
+ });
+ });
+
+ describe('getState()', function () {
+ it('should get a state that represents the... er... state', function () {
+ var state = vis.getState();
+ expect(state).to.have.property('type', 'pie');
+
+ expect(state).to.have.property('params');
+ expect(state.params).to.have.property('isDonut', true);
+
+ expect(state).to.have.property('listeners');
+ expect(state.listeners).to.have.property('click');
+ expect(state.listeners.click).to.eql(_.noop);
+
+ expect(state).to.have.property('aggs');
+ expect(state.aggs).to.have.length(3);
+ });
+ });
+
+ describe('clone()', function () {
+ it('should make clone of itself', function () {
+ var clone = vis.clone();
+ verifyVis(clone);
+ });
+ });
+
+ describe('setState()', function () {
+ it('should set the state to defualts', function () {
+ var vis = new Vis(indexPattern);
+ expect(vis).to.have.property('type');
+ expect(vis.type).to.eql(visTypes.byName['histogram']);
+ expect(vis).to.have.property('aggs');
+ expect(vis.aggs).to.have.length(1);
+ expect(vis).to.have.property('listeners');
+ expect(vis.listeners).to.eql({});
+ expect(vis).to.have.property('params');
+ expect(vis.params).to.have.property('addLegend', true);
+ expect(vis.params).to.have.property('addTooltip', true);
+ expect(vis.params).to.have.property('mode', 'stacked');
+ expect(vis.params).to.have.property('shareYAxis', true);
+ });
+ });
+
+ describe('isHierarchical()', function () {
+ it('should return true for hierarchical vis (like pie)', function () {
+ expect(vis.isHierarchical()).to.be(true);
+ });
+ it('should return false for non-hierarchical vis (like histogram)', function () {
+ var vis = new Vis(indexPattern);
+ expect(vis.isHierarchical()).to.be(false);
+ });
+ });
+
+ });
+});