diff --git a/src/legacy/core_plugins/kibana/public/__tests__/discover/legacy.ts b/src/legacy/core_plugins/kibana/public/__tests__/discover/legacy.ts
deleted file mode 100644
index ecda2a8c15395..0000000000000
--- a/src/legacy/core_plugins/kibana/public/__tests__/discover/legacy.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Licensed to Elasticsearch B.V. under one or more contributor
- * license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright
- * ownership. Elasticsearch B.V. licenses this file to you under
- * the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import { npSetup, npStart } from 'ui/new_platform';
-import { plugin } from '../../../../../../plugins/discover/public';
-import { coreMock } from '../../../../../../core/public/mocks';
-const context = coreMock.createPluginInitializerContext();
-
-export const pluginInstance = plugin(context);
-export const setup = pluginInstance.setup(npSetup.core, npSetup.plugins);
-export const start = pluginInstance.start(npStart.core, npStart.plugins);
diff --git a/src/legacy/core_plugins/kibana/public/__tests__/discover/row_headers.js b/src/legacy/core_plugins/kibana/public/__tests__/discover/row_headers.js
deleted file mode 100644
index 29c301bf065c4..0000000000000
--- a/src/legacy/core_plugins/kibana/public/__tests__/discover/row_headers.js
+++ /dev/null
@@ -1,428 +0,0 @@
-/*
- * Licensed to Elasticsearch B.V. under one or more contributor
- * license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright
- * ownership. Elasticsearch B.V. licenses this file to you under
- * the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-import angular from 'angular';
-import _ from 'lodash';
-import sinon from 'sinon';
-import expect from '@kbn/expect';
-import ngMock from 'ng_mock';
-import { getFakeRow, getFakeRowVals } from 'fixtures/fake_row';
-import $ from 'jquery';
-import { pluginInstance } from './legacy';
-import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern';
-import { setScopedHistory } from '../../../../../../plugins/discover/public/kibana_services';
-import { createBrowserHistory } from 'history';
-
-describe('Doc Table', function () {
- let $parentScope;
- let $scope;
-
- // Stub out a minimal mapping of 4 fields
- let mapping;
-
- let fakeRowVals;
- let stubFieldFormatConverter;
- beforeEach(() => pluginInstance.initializeServices());
- beforeEach(() => pluginInstance.initializeInnerAngular());
- before(() => setScopedHistory(createBrowserHistory()));
- beforeEach(ngMock.module('app/discover'));
- beforeEach(
- ngMock.inject(function ($rootScope, Private) {
- $parentScope = $rootScope;
- $parentScope.indexPattern = Private(FixturesStubbedLogstashIndexPatternProvider);
- mapping = $parentScope.indexPattern.fields;
-
- // Stub `getConverterFor` for a field in the indexPattern to return mock data.
- // Returns `val` if provided, otherwise generates fake data for the field.
- fakeRowVals = getFakeRowVals('formatted', 0, mapping);
- stubFieldFormatConverter = function ($root, field, val) {
- const convertFn = (value, type, options) => {
- if (val) {
- return val;
- }
- const fieldName = _.get(options, 'field.name', null);
-
- return fakeRowVals[fieldName] || '';
- };
-
- $root.indexPattern.fields.getByName(field).format.convert = convertFn;
- $root.indexPattern.fields.getByName(field).format.getConverterFor = () => convertFn;
- };
- })
- );
-
- // Sets up the directive, take an element, and a list of properties to attach to the parent scope.
- const init = function ($elem, props) {
- ngMock.inject(function ($compile) {
- _.assign($parentScope, props);
- $compile($elem)($parentScope);
- $elem.scope().$digest();
- $scope = $elem.isolateScope();
- });
- };
-
- const destroy = function () {
- $scope.$destroy();
- $parentScope.$destroy();
- };
-
- // For testing column removing/adding for the header and the rows
- const columnTests = function (elemType, parentElem) {
- it('should create a time column if the timefield is defined', function () {
- const childElems = parentElem.find(elemType);
- expect(childElems.length).to.be(1);
- });
-
- it('should be able to add and remove columns', function () {
- let childElems;
-
- stubFieldFormatConverter($parentScope, 'bytes');
- stubFieldFormatConverter($parentScope, 'request_body');
-
- // Should include a column for toggling and the time column by default
- $parentScope.columns = ['bytes'];
- parentElem.scope().$digest();
- childElems = parentElem.find(elemType);
- expect(childElems.length).to.be(2);
- expect($(childElems[1]).text()).to.contain('bytes');
-
- $parentScope.columns = ['bytes', 'request_body'];
- parentElem.scope().$digest();
- childElems = parentElem.find(elemType);
- expect(childElems.length).to.be(3);
- expect($(childElems[2]).text()).to.contain('request_body');
-
- $parentScope.columns = ['request_body'];
- parentElem.scope().$digest();
- childElems = parentElem.find(elemType);
- expect(childElems.length).to.be(2);
- expect($(childElems[1]).text()).to.contain('request_body');
- });
-
- it('should create only the toggle column if there is no timeField', function () {
- delete parentElem.scope().indexPattern.timeFieldName;
- parentElem.scope().$digest();
-
- const childElems = parentElem.find(elemType);
- expect(childElems.length).to.be(0);
- });
- };
-
- describe('kbnTableRow', function () {
- const $elem = angular.element(
- '
'
- );
- let row;
-
- beforeEach(function () {
- row = getFakeRow(0, mapping);
-
- init($elem, {
- row,
- columns: [],
- sorting: [],
- filter: sinon.spy(),
- maxLength: 50,
- });
- });
- afterEach(function () {
- destroy();
- });
-
- describe('adding and removing columns', function () {
- columnTests('[data-test-subj~="docTableField"]', $elem);
- });
-
- describe('details row', function () {
- it('should be an empty tr by default', function () {
- expect($elem.next().is('tr')).to.be(true);
- expect($elem.next().text()).to.be('');
- });
-
- it('should expand the detail row when the toggle arrow is clicked', function () {
- $elem.children(':first-child').click();
- $scope.$digest();
- expect($elem.next().text()).to.not.be('');
- });
-
- describe('expanded', function () {
- let $details;
- beforeEach(function () {
- // Open the row
- $scope.toggleRow();
- $scope.$digest();
- $details = $elem.next();
- });
- afterEach(function () {
- // Close the row
- $scope.toggleRow();
- $scope.$digest();
- });
-
- it('should be a tr with something in it', function () {
- expect($details.is('tr')).to.be(true);
- expect($details.text()).to.not.be.empty();
- });
- });
- });
- });
-
- describe('kbnTableRow meta', function () {
- const $elem = angular.element(
- '
'
- );
- let row;
-
- beforeEach(function () {
- row = getFakeRow(0, mapping);
-
- init($elem, {
- row: row,
- columns: [],
- sorting: [],
- filtering: sinon.spy(),
- maxLength: 50,
- });
-
- // Open the row
- $scope.toggleRow();
- $scope.$digest();
- $elem.next();
- });
-
- afterEach(function () {
- destroy();
- });
-
- /** this no longer works with the new plugin approach
- it('should render even when the row source contains a field with the same name as a meta field', function () {
- setTimeout(() => {
- //this should be overridden by later changes
- }, 100);
- expect($details.find('tr').length).to.be(_.keys($parentScope.indexPattern.flattenHit($scope.row)).length);
- }); */
- });
-
- describe('row diffing', function () {
- let $row;
- let $scope;
- let $root;
- let $before;
-
- beforeEach(
- ngMock.inject(function ($rootScope, $compile, Private) {
- $root = $rootScope;
- $root.row = getFakeRow(0, mapping);
- $root.columns = ['_source'];
- $root.sorting = [];
- $root.filtering = sinon.spy();
- $root.maxLength = 50;
- $root.mapping = mapping;
- $root.indexPattern = Private(FixturesStubbedLogstashIndexPatternProvider);
-
- // Stub field format converters for every field in the indexPattern
- $root.indexPattern.fields.forEach((f) => stubFieldFormatConverter($root, f.name));
-
- $row = $('').attr({
- 'kbn-table-row': 'row',
- columns: 'columns',
- sorting: 'sorting',
- filtering: 'filtering',
- 'index-pattern': 'indexPattern',
- });
-
- $scope = $root.$new();
- $compile($row)($scope);
- $root.$apply();
-
- $before = $row.find('td');
- expect($before).to.have.length(3);
- expect($before.eq(0).text().trim()).to.be('');
- expect($before.eq(1).text().trim()).to.match(/^time_formatted/);
- })
- );
-
- afterEach(function () {
- $row.remove();
- });
-
- it('handles a new column', function () {
- $root.columns.push('bytes');
- $root.$apply();
-
- const $after = $row.find('td');
- expect($after).to.have.length(4);
- expect($after[0]).to.be($before[0]);
- expect($after[1]).to.be($before[1]);
- expect($after[2]).to.be($before[2]);
- expect($after.eq(3).text().trim()).to.match(/^bytes_formatted/);
- });
-
- it('handles two new columns at once', function () {
- $root.columns.push('bytes');
- $root.columns.push('request_body');
- $root.$apply();
-
- const $after = $row.find('td');
- expect($after).to.have.length(5);
- expect($after[0]).to.be($before[0]);
- expect($after[1]).to.be($before[1]);
- expect($after[2]).to.be($before[2]);
- expect($after.eq(3).text().trim()).to.match(/^bytes_formatted/);
- expect($after.eq(4).text().trim()).to.match(/^request_body_formatted/);
- });
-
- it('handles three new columns in odd places', function () {
- $root.columns = ['@timestamp', 'bytes', '_source', 'request_body'];
- $root.$apply();
-
- const $after = $row.find('td');
- expect($after).to.have.length(6);
- expect($after[0]).to.be($before[0]);
- expect($after[1]).to.be($before[1]);
- expect($after.eq(2).text().trim()).to.match(/^@timestamp_formatted/);
- expect($after.eq(3).text().trim()).to.match(/^bytes_formatted/);
- expect($after[4]).to.be($before[2]);
- expect($after.eq(5).text().trim()).to.match(/^request_body_formatted/);
- });
-
- it('handles a removed column', function () {
- _.pull($root.columns, '_source');
- $root.$apply();
-
- const $after = $row.find('td');
- expect($after).to.have.length(2);
- expect($after[0]).to.be($before[0]);
- expect($after[1]).to.be($before[1]);
- });
-
- it('handles two removed columns', function () {
- // first add a column
- $root.columns.push('@timestamp');
- $root.$apply();
-
- const $mid = $row.find('td');
- expect($mid).to.have.length(4);
-
- $root.columns.pop();
- $root.columns.pop();
- $root.$apply();
-
- const $after = $row.find('td');
- expect($after).to.have.length(2);
- expect($after[0]).to.be($before[0]);
- expect($after[1]).to.be($before[1]);
- });
-
- it('handles three removed random columns', function () {
- // first add two column
- $root.columns.push('@timestamp', 'bytes');
- $root.$apply();
-
- const $mid = $row.find('td');
- expect($mid).to.have.length(5);
-
- $root.columns[0] = false; // _source
- $root.columns[2] = false; // bytes
- $root.columns = $root.columns.filter(Boolean);
- $root.$apply();
-
- const $after = $row.find('td');
- expect($after).to.have.length(3);
- expect($after[0]).to.be($before[0]);
- expect($after[1]).to.be($before[1]);
- expect($after.eq(2).text().trim()).to.match(/^@timestamp_formatted/);
- });
-
- it('handles two columns with the same content', function () {
- stubFieldFormatConverter($root, 'request_body', fakeRowVals.bytes);
-
- $root.columns.length = 0;
- $root.columns.push('bytes');
- $root.columns.push('request_body');
- $root.$apply();
-
- const $after = $row.find('td');
- expect($after).to.have.length(4);
- expect($after.eq(2).text().trim()).to.match(/^bytes_formatted/);
- expect($after.eq(3).text().trim()).to.match(/^bytes_formatted/);
- });
-
- it('handles two columns swapping position', function () {
- $root.columns.push('bytes');
- $root.$apply();
-
- const $mid = $row.find('td');
- expect($mid).to.have.length(4);
-
- $root.columns.reverse();
- $root.$apply();
-
- const $after = $row.find('td');
- expect($after).to.have.length(4);
- expect($after[0]).to.be($before[0]);
- expect($after[1]).to.be($before[1]);
- expect($after[2]).to.be($mid[3]);
- expect($after[3]).to.be($mid[2]);
- });
-
- it('handles four columns all reversing position', function () {
- $root.columns.push('bytes', 'response', '@timestamp');
- $root.$apply();
-
- const $mid = $row.find('td');
- expect($mid).to.have.length(6);
-
- $root.columns.reverse();
- $root.$apply();
-
- const $after = $row.find('td');
- expect($after).to.have.length(6);
- expect($after[0]).to.be($before[0]);
- expect($after[1]).to.be($before[1]);
- expect($after[2]).to.be($mid[5]);
- expect($after[3]).to.be($mid[4]);
- expect($after[4]).to.be($mid[3]);
- expect($after[5]).to.be($mid[2]);
- });
-
- it('handles multiple columns with the same name', function () {
- $root.columns.push('bytes', 'bytes', 'bytes');
- $root.$apply();
-
- const $after = $row.find('td');
- expect($after).to.have.length(6);
- expect($after[0]).to.be($before[0]);
- expect($after[1]).to.be($before[1]);
- expect($after[2]).to.be($before[2]);
- expect($after.eq(3).text().trim()).to.match(/^bytes_formatted/);
- expect($after.eq(4).text().trim()).to.match(/^bytes_formatted/);
- expect($after.eq(5).text().trim()).to.match(/^bytes_formatted/);
- });
- });
-});
diff --git a/src/plugins/discover/public/application/angular/directives/fixed_scroll.test.js b/src/plugins/discover/public/application/angular/directives/fixed_scroll.test.js
index 16293ca621e05..65255d6c0c4a4 100644
--- a/src/plugins/discover/public/application/angular/directives/fixed_scroll.test.js
+++ b/src/plugins/discover/public/application/angular/directives/fixed_scroll.test.js
@@ -230,6 +230,10 @@ describe('FixedScroll directive', function () {
$to = els[names.to];
});
+ afterAll(() => {
+ delete angular.element.prototype.scrollLeft;
+ });
+
test('transfers the scrollLeft', function () {
expect(spyJQueryScrollLeft.callCount).toBe(0);
expect(spyJQLiteScrollLeft.callCount).toBe(0);
diff --git a/src/plugins/discover/public/application/angular/doc_table/components/row_headers.test.js b/src/plugins/discover/public/application/angular/doc_table/components/row_headers.test.js
new file mode 100644
index 0000000000000..b30b13b1f0b6e
--- /dev/null
+++ b/src/plugins/discover/public/application/angular/doc_table/components/row_headers.test.js
@@ -0,0 +1,485 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import angular from 'angular';
+import 'angular-mocks';
+import 'angular-sanitize';
+import 'angular-route';
+import _ from 'lodash';
+import sinon from 'sinon';
+import { getFakeRow, getFakeRowVals } from 'fixtures/fake_row';
+import $ from 'jquery';
+import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern';
+import { setScopedHistory, setServices, setDocViewsRegistry } from '../../../../kibana_services';
+import { coreMock } from '../../../../../../../core/public/mocks';
+import { dataPluginMock } from '../../../../../../data/public/mocks';
+import { navigationPluginMock } from '../../../../../../navigation/public/mocks';
+import { getInnerAngularModule } from '../../../../get_inner_angular';
+import { createBrowserHistory } from 'history';
+
+describe('Doc Table', () => {
+ const core = coreMock.createStart();
+ const dataMock = dataPluginMock.createStartContract();
+ let $parentScope;
+ let $scope;
+ let $elementScope;
+ let timeout;
+ let registry = [];
+
+ // Stub out a minimal mapping of 4 fields
+ let mapping;
+
+ let fakeRowVals;
+ let stubFieldFormatConverter;
+ beforeAll(() => setScopedHistory(createBrowserHistory()));
+ beforeEach(() => {
+ angular.element.prototype.slice = jest.fn(function (index) {
+ return $(this).slice(index);
+ });
+ angular.element.prototype.filter = jest.fn(function (condition) {
+ return $(this).filter(condition);
+ });
+ angular.element.prototype.toggle = jest.fn(function (name) {
+ return $(this).toggle(name);
+ });
+ angular.element.prototype.is = jest.fn(function (name) {
+ return $(this).is(name);
+ });
+ setServices({
+ uiSettings: core.uiSettings,
+ filterManager: dataMock.query.filterManager,
+ });
+
+ setDocViewsRegistry({
+ addDocView(view) {
+ registry.push(view);
+ },
+ getDocViewsSorted() {
+ return registry;
+ },
+ resetRegistry: () => {
+ registry = [];
+ },
+ });
+
+ getInnerAngularModule(
+ 'app/discover',
+ core,
+ {
+ data: dataMock,
+ navigation: navigationPluginMock.createStartContract(),
+ },
+ coreMock.createPluginInitializerContext()
+ );
+ angular.mock.module('app/discover');
+ });
+ beforeEach(
+ angular.mock.inject(function ($rootScope, Private, $timeout) {
+ $parentScope = $rootScope;
+ timeout = $timeout;
+ $parentScope.indexPattern = Private(FixturesStubbedLogstashIndexPatternProvider);
+ mapping = $parentScope.indexPattern.fields;
+
+ // Stub `getConverterFor` for a field in the indexPattern to return mock data.
+ // Returns `val` if provided, otherwise generates fake data for the field.
+ fakeRowVals = getFakeRowVals('formatted', 0, mapping);
+ stubFieldFormatConverter = function ($root, field, val) {
+ const convertFn = (value, type, options) => {
+ if (val) {
+ return val;
+ }
+ const fieldName = _.get(options, 'field.name', null);
+
+ return fakeRowVals[fieldName] || '';
+ };
+
+ $root.indexPattern.fields.getByName(field).format.convert = convertFn;
+ $root.indexPattern.fields.getByName(field).format.getConverterFor = () => convertFn;
+ };
+ })
+ );
+
+ afterEach(() => {
+ delete angular.element.prototype.slice;
+ delete angular.element.prototype.filter;
+ delete angular.element.prototype.toggle;
+ delete angular.element.prototype.is;
+ });
+
+ // Sets up the directive, take an element, and a list of properties to attach to the parent scope.
+ const init = function ($elem, props) {
+ angular.mock.inject(function ($compile) {
+ _.assign($parentScope, props);
+ const el = $compile($elem)($parentScope);
+ $elementScope = el.scope();
+ el.scope().$digest();
+ $scope = el.isolateScope();
+ });
+ };
+
+ const destroy = () => {
+ $scope.$destroy();
+ $parentScope.$destroy();
+ };
+
+ // For testing column removing/adding for the header and the rows
+ const columnTests = function (elemType, parentElem) {
+ test('should create a time column if the timefield is defined', () => {
+ const childElems = parentElem.find(elemType);
+ expect(childElems.length).toBe(1);
+ });
+
+ test('should be able to add and remove columns', () => {
+ let childElems;
+
+ stubFieldFormatConverter($parentScope, 'bytes');
+ stubFieldFormatConverter($parentScope, 'request_body');
+
+ // Should include a column for toggling and the time column by default
+ $parentScope.columns = ['bytes'];
+ $elementScope.$digest();
+ childElems = parentElem.find(elemType);
+ expect(childElems.length).toBe(2);
+ expect($(childElems[1]).text()).toContain('bytes');
+
+ $parentScope.columns = ['bytes', 'request_body'];
+ $elementScope.$digest();
+ childElems = parentElem.find(elemType);
+ expect(childElems.length).toBe(3);
+ expect($(childElems[2]).text()).toContain('request_body');
+
+ $parentScope.columns = ['request_body'];
+ $elementScope.$digest();
+ childElems = parentElem.find(elemType);
+ expect(childElems.length).toBe(2);
+ expect($(childElems[1]).text()).toContain('request_body');
+ });
+
+ test('should create only the toggle column if there is no timeField', () => {
+ delete $scope.indexPattern.timeFieldName;
+ $scope.$digest();
+ timeout.flush();
+
+ const childElems = parentElem.find(elemType);
+ expect(childElems.length).toBe(0);
+ });
+ };
+
+ describe('kbnTableRow', () => {
+ const $elem = $(
+ '
'
+ );
+ let row;
+
+ beforeEach(() => {
+ row = getFakeRow(0, mapping);
+
+ init($elem, {
+ row,
+ columns: [],
+ sorting: [],
+ filter: sinon.spy(),
+ maxLength: 50,
+ });
+ });
+ afterEach(() => {
+ destroy();
+ });
+
+ describe('adding and removing columns', () => {
+ columnTests('[data-test-subj~="docTableField"]', $elem);
+ });
+
+ describe('details row', () => {
+ test('should be an empty tr by default', () => {
+ expect($elem.next().is('tr')).toBe(true);
+ expect($elem.next().text()).toBe('');
+ });
+
+ test('should expand the detail row when the toggle arrow is clicked', () => {
+ $elem.children(':first-child').click();
+ expect($elem.next().text()).not.toBe('');
+ });
+
+ describe('expanded', () => {
+ let $details;
+ beforeEach(() => {
+ // Open the row
+ $scope.toggleRow();
+ timeout.flush();
+ $details = $elem.next();
+ });
+ afterEach(() => {
+ // Close the row
+ $scope.toggleRow();
+ });
+
+ test('should be a tr with something in it', () => {
+ expect($details.is('tr')).toBe(true);
+ expect($details.text()).toBeTruthy();
+ });
+ });
+ });
+ });
+
+ describe('kbnTableRow meta', () => {
+ const $elem = angular.element(
+ '
'
+ );
+ let row;
+
+ beforeEach(() => {
+ row = getFakeRow(0, mapping);
+
+ init($elem, {
+ row: row,
+ columns: [],
+ sorting: [],
+ filtering: sinon.spy(),
+ maxLength: 50,
+ });
+
+ // Open the row
+ $scope.toggleRow();
+ $scope.$digest();
+ timeout.flush();
+ $elem.next();
+ });
+
+ afterEach(() => {
+ destroy();
+ });
+
+ /** this no longer works with the new plugin approach
+ test('should render even when the row source contains a field with the same name as a meta field', () => {
+ setTimeout(() => {
+ //this should be overridden by later changes
+ }, 100);
+ expect($details.find('tr').length).toBe(_.keys($parentScope.indexPattern.flattenHit($scope.row)).length);
+ }); */
+ });
+
+ describe('row diffing', () => {
+ let $row;
+ let $scope;
+ let $root;
+ let $before;
+
+ beforeEach(
+ angular.mock.inject(function ($rootScope, $compile, Private) {
+ $root = $rootScope;
+ $root.row = getFakeRow(0, mapping);
+ $root.columns = ['_source'];
+ $root.sorting = [];
+ $root.filtering = sinon.spy();
+ $root.maxLength = 50;
+ $root.mapping = mapping;
+ $root.indexPattern = Private(FixturesStubbedLogstashIndexPatternProvider);
+
+ // Stub field format converters for every field in the indexPattern
+ $root.indexPattern.fields.forEach((f) => stubFieldFormatConverter($root, f.name));
+
+ $row = $('').attr({
+ 'kbn-table-row': 'row',
+ columns: 'columns',
+ sorting: 'sorting',
+ filtering: 'filtering',
+ 'index-pattern': 'indexPattern',
+ });
+
+ $scope = $root.$new();
+ $compile($row)($scope);
+ $root.$apply();
+
+ $before = $row.find('td');
+ expect($before).toHaveLength(3);
+ expect($before.eq(0).text().trim()).toBe('');
+ expect($before.eq(1).text().trim()).toMatch(/^time_formatted/);
+ })
+ );
+
+ afterEach(() => {
+ $row.remove();
+ });
+
+ test('handles a new column', () => {
+ $root.columns.push('bytes');
+ $root.$apply();
+
+ const $after = $row.find('td');
+ expect($after).toHaveLength(4);
+ expect($after[0].outerHTML).toBe($before[0].outerHTML);
+ expect($after[1].outerHTML).toBe($before[1].outerHTML);
+ expect($after[2].outerHTML).toBe($before[2].outerHTML);
+ expect($after.eq(3).text().trim()).toMatch(/^bytes_formatted/);
+ });
+
+ test('handles two new columns at once', () => {
+ $root.columns.push('bytes');
+ $root.columns.push('request_body');
+ $root.$apply();
+
+ const $after = $row.find('td');
+ expect($after).toHaveLength(5);
+ expect($after[0].outerHTML).toBe($before[0].outerHTML);
+ expect($after[1].outerHTML).toBe($before[1].outerHTML);
+ expect($after[2].outerHTML).toBe($before[2].outerHTML);
+ expect($after.eq(3).text().trim()).toMatch(/^bytes_formatted/);
+ expect($after.eq(4).text().trim()).toMatch(/^request_body_formatted/);
+ });
+
+ test('handles three new columns in odd places', () => {
+ $root.columns = ['@timestamp', 'bytes', '_source', 'request_body'];
+ $root.$apply();
+
+ const $after = $row.find('td');
+ expect($after).toHaveLength(6);
+ expect($after[0].outerHTML).toBe($before[0].outerHTML);
+ expect($after[1].outerHTML).toBe($before[1].outerHTML);
+ expect($after.eq(2).text().trim()).toMatch(/^@timestamp_formatted/);
+ expect($after.eq(3).text().trim()).toMatch(/^bytes_formatted/);
+ expect($after[4].outerHTML).toBe($before[2].outerHTML);
+ expect($after.eq(5).text().trim()).toMatch(/^request_body_formatted/);
+ });
+
+ test('handles a removed column', () => {
+ _.pull($root.columns, '_source');
+ $root.$apply();
+
+ const $after = $row.find('td');
+ expect($after).toHaveLength(2);
+ expect($after[0].outerHTML).toBe($before[0].outerHTML);
+ expect($after[1].outerHTML).toBe($before[1].outerHTML);
+ });
+
+ test('handles two removed columns', () => {
+ // first add a column
+ $root.columns.push('@timestamp');
+ $root.$apply();
+
+ const $mid = $row.find('td');
+ expect($mid).toHaveLength(4);
+
+ $root.columns.pop();
+ $root.columns.pop();
+ $root.$apply();
+
+ const $after = $row.find('td');
+ expect($after).toHaveLength(2);
+ expect($after[0].outerHTML).toBe($before[0].outerHTML);
+ expect($after[1].outerHTML).toBe($before[1].outerHTML);
+ });
+
+ test('handles three removed random columns', () => {
+ // first add two column
+ $root.columns.push('@timestamp', 'bytes');
+ $root.$apply();
+
+ const $mid = $row.find('td');
+ expect($mid).toHaveLength(5);
+
+ $root.columns[0] = false; // _source
+ $root.columns[2] = false; // bytes
+ $root.columns = $root.columns.filter(Boolean);
+ $root.$apply();
+
+ const $after = $row.find('td');
+ expect($after).toHaveLength(3);
+ expect($after[0].outerHTML).toBe($before[0].outerHTML);
+ expect($after[1].outerHTML).toBe($before[1].outerHTML);
+ expect($after.eq(2).text().trim()).toMatch(/^@timestamp_formatted/);
+ });
+
+ test('handles two columns with the same content', () => {
+ stubFieldFormatConverter($root, 'request_body', fakeRowVals.bytes);
+
+ $root.columns.length = 0;
+ $root.columns.push('bytes');
+ $root.columns.push('request_body');
+ $root.$apply();
+
+ const $after = $row.find('td');
+ expect($after).toHaveLength(4);
+ expect($after.eq(2).text().trim()).toMatch(/^bytes_formatted/);
+ expect($after.eq(3).text().trim()).toMatch(/^bytes_formatted/);
+ });
+
+ test('handles two columns swapping position', () => {
+ $root.columns.push('bytes');
+ $root.$apply();
+
+ const $mid = $row.find('td');
+ expect($mid).toHaveLength(4);
+
+ $root.columns.reverse();
+ $root.$apply();
+
+ const $after = $row.find('td');
+ expect($after).toHaveLength(4);
+ expect($after[0].outerHTML).toBe($before[0].outerHTML);
+ expect($after[1].outerHTML).toBe($before[1].outerHTML);
+ expect($after[2].outerHTML).toBe($mid[3].outerHTML);
+ expect($after[3].outerHTML).toBe($mid[2].outerHTML);
+ });
+
+ test('handles four columns all reversing position', () => {
+ $root.columns.push('bytes', 'response', '@timestamp');
+ $root.$apply();
+
+ const $mid = $row.find('td');
+ expect($mid).toHaveLength(6);
+
+ $root.columns.reverse();
+ $root.$apply();
+
+ const $after = $row.find('td');
+ expect($after).toHaveLength(6);
+ expect($after[0].outerHTML).toBe($before[0].outerHTML);
+ expect($after[1].outerHTML).toBe($before[1].outerHTML);
+ expect($after[2].outerHTML).toBe($mid[5].outerHTML);
+ expect($after[3].outerHTML).toBe($mid[4].outerHTML);
+ expect($after[4].outerHTML).toBe($mid[3].outerHTML);
+ expect($after[5].outerHTML).toBe($mid[2].outerHTML);
+ });
+
+ test('handles multiple columns with the same name', () => {
+ $root.columns.push('bytes', 'bytes', 'bytes');
+ $root.$apply();
+
+ const $after = $row.find('td');
+ expect($after).toHaveLength(6);
+ expect($after[0].outerHTML).toBe($before[0].outerHTML);
+ expect($after[1].outerHTML).toBe($before[1].outerHTML);
+ expect($after[2].outerHTML).toBe($before[2].outerHTML);
+ expect($after.eq(3).text().trim()).toMatch(/^bytes_formatted/);
+ expect($after.eq(4).text().trim()).toMatch(/^bytes_formatted/);
+ expect($after.eq(5).text().trim()).toMatch(/^bytes_formatted/);
+ });
+ });
+});
diff --git a/src/legacy/core_plugins/kibana/public/__tests__/discover/doc_table.js b/src/plugins/discover/public/application/angular/doc_table/doc_table.test.js
similarity index 52%
rename from src/legacy/core_plugins/kibana/public/__tests__/discover/doc_table.js
rename to src/plugins/discover/public/application/angular/doc_table/doc_table.test.js
index 504b00808718b..9722981df42b1 100644
--- a/src/legacy/core_plugins/kibana/public/__tests__/discover/doc_table.js
+++ b/src/plugins/discover/public/application/angular/doc_table/doc_table.test.js
@@ -17,15 +17,18 @@
* under the License.
*/
import angular from 'angular';
-import expect from '@kbn/expect';
import _ from 'lodash';
-import ngMock from 'ng_mock';
-import 'ui/private';
-import { pluginInstance } from './legacy';
+import 'angular-mocks';
+import 'angular-sanitize';
+import 'angular-route';
+import { createBrowserHistory } from 'history';
import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern';
import hits from 'fixtures/real_hits';
-import { setScopedHistory } from '../../../../../../plugins/discover/public/kibana_services';
-import { createBrowserHistory } from 'history';
+import { coreMock } from '../../../../../../core/public/mocks';
+import { dataPluginMock } from '../../../../../data/public/mocks';
+import { navigationPluginMock } from '../../../../../navigation/public/mocks';
+import { setScopedHistory, setServices } from '../../../kibana_services';
+import { getInnerAngularModule } from '../../../get_inner_angular';
let $parentScope;
@@ -36,7 +39,7 @@ let $timeout;
let indexPattern;
const init = function ($elem, props) {
- ngMock.inject(function ($rootScope, $compile, _$timeout_) {
+ angular.mock.inject(function ($rootScope, $compile, _$timeout_) {
$timeout = _$timeout_;
$parentScope = $rootScope;
_.assign($parentScope, props);
@@ -44,7 +47,7 @@ const init = function ($elem, props) {
$compile($elem)($parentScope);
// I think the prereq requires this?
- $timeout(function () {
+ $timeout(() => {
$elem.scope().$digest();
}, 0);
@@ -52,19 +55,40 @@ const init = function ($elem, props) {
});
};
-const destroy = function () {
+const destroy = () => {
$scope.$destroy();
$parentScope.$destroy();
};
-describe('docTable', function () {
+describe('docTable', () => {
+ const core = coreMock.createStart();
let $elem;
- before(() => setScopedHistory(createBrowserHistory()));
- beforeEach(() => pluginInstance.initializeInnerAngular());
- beforeEach(() => pluginInstance.initializeServices());
- beforeEach(ngMock.module('app/discover'));
- beforeEach(function () {
+ beforeAll(() => setScopedHistory(createBrowserHistory()));
+ beforeEach(() => {
+ angular.element.prototype.slice = jest.fn(() => {
+ return null;
+ });
+ angular.element.prototype.filter = jest.fn(() => {
+ return {
+ remove: jest.fn(),
+ };
+ });
+ setServices({
+ uiSettings: core.uiSettings,
+ });
+ getInnerAngularModule(
+ 'app/discover',
+ core,
+ {
+ data: dataPluginMock.createStartContract(),
+ navigation: navigationPluginMock.createStartContract(),
+ },
+ coreMock.createPluginInitializerContext()
+ );
+ angular.mock.module('app/discover');
+ });
+ beforeEach(() => {
$elem = angular.element(`
`);
- ngMock.inject(function (Private) {
+ angular.mock.inject(function (Private) {
indexPattern = Private(FixturesStubbedLogstashIndexPatternProvider);
});
init($elem, {
@@ -87,34 +111,36 @@ describe('docTable', function () {
$scope.$digest();
});
- afterEach(function () {
+ afterEach(() => {
+ delete angular.element.prototype.slice;
+ delete angular.element.prototype.filter;
destroy();
});
- it('should compile', function () {
- expect($elem.text()).to.not.be.empty();
+ test('should compile', () => {
+ expect($elem.text()).toBeTruthy();
});
- it('should have an addRows function that increases the row count', function () {
- expect($scope.addRows).to.be.a(Function);
+ test('should have an addRows function that increases the row count', () => {
+ expect($scope.addRows).toBeInstanceOf(Function);
$scope.$digest();
- expect($scope.limit).to.be(50);
+ expect($scope.limit).toBe(50);
$scope.addRows();
- expect($scope.limit).to.be(100);
+ expect($scope.limit).toBe(100);
});
- it('should reset the row limit when results are received', function () {
+ test('should reset the row limit when results are received', () => {
$scope.limit = 100;
- expect($scope.limit).to.be(100);
+ expect($scope.limit).toBe(100);
$scope.hits = [...hits];
$scope.$digest();
- expect($scope.limit).to.be(50);
+ expect($scope.limit).toBe(50);
});
- it('should have a header and a table element', function () {
+ test('should have a header and a table element', () => {
$scope.$digest();
- expect($elem.find('thead').length).to.be(1);
- expect($elem.find('table').length).to.be(1);
+ expect($elem.find('thead').length).toBe(1);
+ expect($elem.find('table').length).toBe(1);
});
});