diff --git a/x-pack/plugins/rollup/__jest__/utils/testbed.js b/x-pack/plugins/rollup/__jest__/utils/testbed.js
index 95ef83dd1b928..dab5d1e7d93ba 100644
--- a/x-pack/plugins/rollup/__jest__/utils/testbed.js
+++ b/x-pack/plugins/rollup/__jest__/utils/testbed.js
@@ -9,7 +9,7 @@ import { Provider } from 'react-redux';
import { mountWithIntl } from 'test_utils/enzyme_helpers'; // eslint-disable-line import/no-unresolved
import { findTestSubject as findTestSubjectHelper } from '@elastic/eui/lib/test';
-const registerTestSubjExists = component => testSubject => Boolean(findTestSubjectHelper(component, testSubject).length);
+const registerTestSubjExists = component => (testSubject, count = 1) => findTestSubjectHelper(component, testSubject).length === count;
export const registerTestBed = (Component, defaultProps, store = {}) => (props) => {
const component = mountWithIntl(
diff --git a/x-pack/plugins/rollup/fixtures/job.js b/x-pack/plugins/rollup/fixtures/job.js
index ba9352dd36404..b8aab4da6bd9d 100644
--- a/x-pack/plugins/rollup/fixtures/job.js
+++ b/x-pack/plugins/rollup/fixtures/job.js
@@ -10,34 +10,38 @@ const initialValues = {
dateHistogramField: 'timestamp',
dateHistogramInterval: '24h',
dateHistogramTimeZone: 'UTC',
- documentsProcessed: 0,
+ documentsProcessed: 10,
histogram: [
{ name: 'DistanceMiles' },
{ name: 'FlightTimeMin' },
],
id: 'test',
indexPattern: 'kibana*',
+ json: {
+ foo: 'bar',
+ },
metrics: [
{
name: 'dayOfWeek',
- types: ['avg', 'min']
+ types: ['avg', 'max', 'min']
},
{
name: 'distanceKilometers',
types: ['avg', 'max']
}
],
- pagesProcessed: 0,
+ pagesProcessed: 3,
rollupCron: '0 0 0 ? * 7',
rollupDelay: '1d',
rollupIndex: 'my_rollup_index',
- rollupsIndexed: 0,
+ rollupsIndexed: 2,
status: 'stopped',
terms: [
+ { name: 'Dest' },
{ name: 'Carrier' },
{ name: 'DestCountry' },
],
- triggerCount: 0,
+ triggerCount: 7,
};
export const getJob = (values = { id: getRandomString() }) => ({ ...initialValues, ...values });
diff --git a/x-pack/plugins/rollup/public/crud_app/sections/components/field_list/field_list.js b/x-pack/plugins/rollup/public/crud_app/sections/components/field_list/field_list.js
index 912b945a0d7e0..e0c1fdf2222b2 100644
--- a/x-pack/plugins/rollup/public/crud_app/sections/components/field_list/field_list.js
+++ b/x-pack/plugins/rollup/public/crud_app/sections/components/field_list/field_list.js
@@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import React, { Fragment } from 'react';
+import React from 'react';
import PropTypes from 'prop-types';
import {
@@ -64,17 +64,15 @@ export const FieldList = ({
};
return (
-
-
-
+
);
};
diff --git a/x-pack/plugins/rollup/public/crud_app/sections/components/job_details/tabs/tab_summary.js b/x-pack/plugins/rollup/public/crud_app/sections/components/job_details/tabs/tab_summary.js
index 16d65f295d9d5..04d064639c257 100644
--- a/x-pack/plugins/rollup/public/crud_app/sections/components/job_details/tabs/tab_summary.js
+++ b/x-pack/plugins/rollup/public/crud_app/sections/components/job_details/tabs/tab_summary.js
@@ -43,11 +43,17 @@ export class TabSummary extends Component {
} = stats;
return (
-
+
-
+
-
+
-
+
{documentsProcessed}
-
+
-
+
{pagesProcessed}
@@ -92,34 +100,36 @@ export class TabSummary extends Component {
-
+
-
+
{rollupsIndexed}
-
+
-
+
{triggerCount}
-
+
);
}
@@ -138,154 +148,186 @@ export class TabSummary extends Component {
return (
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {indexPattern}
+
+
+
+
+
+
+
-
-
-
-
-
-
-
- {indexPattern}
-
-
+
+ {rollupIndex}
+
+
+
-
-
-
-
+
+
+
+ {' '}
+
+ )}
+ />
+
+
+ {rollupCron}
+
+
-
- {rollupIndex}
-
-
-
+
+
+
+
-
-
-
- {' '}
-
+ {rollupDelay || (
)}
- />
-
-
-
- {rollupCron}
-
-
-
-
-
-
-
-
-
- {rollupDelay || (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
- )}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {dateHistogramField}
-
-
-
-
-
-
-
+
+
+
+ {dateHistogramField}
+
+
+
+
+
+
+
-
- {dateHistogramTimeZone}
-
-
-
+
+ {dateHistogramTimeZone}
+
+
+
-
-
-
- {' '}
-
- )}
- />
-
-
-
- {dateHistogramInterval}
-
-
-
-
+
+
+
+ {' '}
+
+ )}
+ />
+
+
+
+ {dateHistogramInterval}
+
+
+
+
+
{this.renderStats()}
diff --git a/x-pack/plugins/rollup/public/crud_app/sections/job_list/detail_panel/detail_panel.js b/x-pack/plugins/rollup/public/crud_app/sections/job_list/detail_panel/detail_panel.js
index b080c61d430be..85ff06bb016de 100644
--- a/x-pack/plugins/rollup/public/crud_app/sections/job_list/detail_panel/detail_panel.js
+++ b/x-pack/plugins/rollup/public/crud_app/sections/job_list/detail_panel/detail_panel.js
@@ -37,7 +37,7 @@ import {
tabToHumanizedMap,
} from '../../components';
-const JOB_DETAILS_TABS = [
+export const JOB_DETAILS_TABS = [
JOB_DETAILS_TAB_SUMMARY,
JOB_DETAILS_TAB_TERMS,
JOB_DETAILS_TAB_HISTOGRAM,
@@ -50,6 +50,7 @@ export class DetailPanelUi extends Component {
isOpen: PropTypes.bool.isRequired,
isLoading: PropTypes.bool,
job: PropTypes.object,
+ jobId: PropTypes.string,
panelType: PropTypes.oneOf(JOB_DETAILS_TABS),
closeDetailPanel: PropTypes.func.isRequired,
openDetailPanel: PropTypes.func.isRequired,
@@ -137,7 +138,7 @@ export class DetailPanelUi extends Component {
return (
-
+
+
+
-
+
{jobId}
diff --git a/x-pack/plugins/rollup/public/crud_app/sections/job_list/detail_panel/detail_panel.test.js b/x-pack/plugins/rollup/public/crud_app/sections/job_list/detail_panel/detail_panel.test.js
new file mode 100644
index 0000000000000..0470a1ff47019
--- /dev/null
+++ b/x-pack/plugins/rollup/public/crud_app/sections/job_list/detail_panel/detail_panel.test.js
@@ -0,0 +1,335 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { registerTestBed } from '../../../../../__jest__/utils';
+import { getJob } from '../../../../../fixtures';
+import { rollupJobsStore } from '../../../store';
+import { DetailPanel } from './detail_panel';
+import {
+ JOB_DETAILS_TAB_SUMMARY,
+ JOB_DETAILS_TAB_TERMS,
+ JOB_DETAILS_TAB_HISTOGRAM,
+ JOB_DETAILS_TAB_METRICS,
+ JOB_DETAILS_TAB_JSON,
+ tabToHumanizedMap,
+} from '../../components';
+
+const defaultJob = getJob();
+
+const defaultProps = {
+ isOpen: true,
+ isLoading: false,
+ job: defaultJob,
+ jobId: defaultJob.id,
+ panelType: JOB_DETAILS_TAB_SUMMARY,
+ closeDetailPanel: jest.fn(),
+ openDetailPanel: jest.fn(),
+};
+
+const initTestBed = registerTestBed(DetailPanel, defaultProps, rollupJobsStore);
+
+describe('', () => {
+ describe('layout', () => {
+ let component;
+ let findTestSubject;
+ let testSubjectExists;
+
+ beforeEach(() => {
+ ({ component, findTestSubject } = initTestBed());
+ });
+
+ it('should have the title set to the current Job "id"', () => {
+ const { job } = defaultProps;
+ const title = findTestSubject('rollupJobDetailsFlyoutTitle');
+ expect(title.length).toBe(1);
+ expect(title.text()).toEqual(job.id);
+ });
+
+ it('should have children if it\'s open', () => {
+ expect(component.find('DetailPanelUi').children().length).toBeTruthy();
+ });
+
+ it('should *not* have children if it\s closed', () => {
+ ({ component } = initTestBed({ isOpen: false }));
+ expect(component.find('DetailPanelUi').children().length).toBeFalsy();
+ });
+
+ it('should show a loading when the job is loading', () => {
+ ({ component, findTestSubject, testSubjectExists } = initTestBed({ isLoading: true }));
+ const loading = findTestSubject('rollupJobDetailLoading');
+ expect(loading.length).toBeTruthy();
+ expect(loading.text()).toEqual('Loading rollup job...');
+
+ // Make sure the title and the tabs are visible
+ expect(testSubjectExists('detailPanelTabSelected')).toBeTruthy();
+ expect(testSubjectExists('rollupJobDetailsFlyoutTitle')).toBeTruthy();
+ });
+
+ it('should display a message when no job is provided', () => {
+ ({ component, findTestSubject } = initTestBed({ job: undefined }));
+ expect(findTestSubject('rollupJobDetailJobNotFound').text()).toEqual('Rollup job not found');
+ });
+ });
+
+ describe('tabs', () => {
+ const tabActive = JOB_DETAILS_TAB_SUMMARY;
+ const { component } = initTestBed({ panelType: tabActive });
+ const tabs = component.find('EuiTab');
+ const getTab = (id) => {
+ const found = tabs.findWhere((tab) => {
+ return tab.text() === tabToHumanizedMap[id].props.defaultMessage;
+ });
+ return found.first();
+ };
+
+ it('should have 5 tabs visible', () => {
+ const tabsLabel = tabs.map(tab => tab.text());
+
+ expect(tabsLabel).toEqual(['Summary', 'Terms', 'Histogram', 'Metrics', 'JSON']);
+ });
+
+ it('should set default selected tab to the "panelType" prop provided', () => {
+ const tab = getTab(tabActive);
+ expect(tab.props().isSelected).toEqual(true);
+ });
+
+ it('should select the tab when clicking on it', () => {
+ const { job, openDetailPanel } = defaultProps;
+ const termsTab = getTab(JOB_DETAILS_TAB_TERMS);
+
+ termsTab.simulate('click');
+
+ expect(openDetailPanel.mock.calls.length).toBe(1);
+ expect(openDetailPanel.mock.calls[0][0]).toEqual({
+ jobId: job.id,
+ panelType: JOB_DETAILS_TAB_TERMS
+ });
+ });
+ });
+
+ describe('job detail', () => {
+ describe('summary tab content', () => {
+ // Init testBed on the SUMMARY tab
+ const panelType = JOB_DETAILS_TAB_SUMMARY;
+ const { findTestSubject } = initTestBed({ panelType });
+
+ it('should have a "Logistics", "Date histogram" and "Stats" section', () => {
+ const expectedSections = ['Logistics', 'DateHistogram', 'Stats'];
+ const sectionsFound = expectedSections.reduce((sectionsFound, section) => {
+ if (findTestSubject(`rollupJobDetailSummary${section}Section`).length) {
+ sectionsFound.push(section);
+ }
+ return sectionsFound;
+ }, []);
+
+ expect(sectionsFound).toEqual(expectedSections);
+ });
+
+ describe('Logistics section', () => {
+ const LOGISTICS_SUBSECTIONS = ['IndexPattern', 'RollupIndex', 'Cron', 'Delay'];
+
+ it('should have "Index pattern", "Rollup index", "Cron" and "Delay" subsections', () => {
+ const logisticsSubsectionsTitles = LOGISTICS_SUBSECTIONS.reduce((subSections, subSection) => {
+ if (findTestSubject(`rollupJobDetailLogistics${subSection}Title`)) {
+ subSections.push(subSection);
+ }
+ return subSections;
+ }, []);
+ expect(logisticsSubsectionsTitles).toEqual(LOGISTICS_SUBSECTIONS);
+ });
+
+ it('should set the correct job value for each of the subsection', () => {
+ LOGISTICS_SUBSECTIONS.forEach((subSection) => {
+ const wrapper = findTestSubject(`rollupJobDetailLogistics${subSection}Description`);
+ expect(wrapper.length).toBe(1);
+ const description = wrapper.text();
+
+ switch(subSection) {
+ case 'IndexPattern':
+ expect(description).toEqual(defaultJob.indexPattern);
+ break;
+ case 'Cron':
+ expect(description).toEqual(defaultJob.rollupCron);
+ break;
+ case 'Delay':
+ expect(description).toEqual(defaultJob.rollupDelay);
+ break;
+ case 'RollupIndex':
+ expect(description).toEqual(defaultJob.rollupIndex);
+ break;
+ default:
+ // Should never get here... if it does a section is missing in the constant
+ throw(new Error('Should not get here. The constant LOGISTICS_SUBSECTIONS is probably missing a new subsection'));
+ }
+ });
+ });
+ });
+
+ describe('Date histogram section', () => {
+ const DATE_HISTOGRAMS_SUBSECTIONS = ['TimeField', 'Timezone', 'Interval'];
+
+ it('should have "Time field", "Timezone", "Interval" subsections', () => {
+ const dateHistogramSubsections = DATE_HISTOGRAMS_SUBSECTIONS.reduce((subSections, subSection) => {
+ if (findTestSubject(`rollupJobDetailDateHistogram${subSection}Title`)) {
+ subSections.push(subSection);
+ }
+ return subSections;
+ }, []);
+ expect(dateHistogramSubsections).toEqual(DATE_HISTOGRAMS_SUBSECTIONS);
+ });
+
+ it('should set the correct job value for each of the subsection', () => {
+ DATE_HISTOGRAMS_SUBSECTIONS.forEach((subSection) => {
+ const wrapper = findTestSubject(`rollupJobDetailDateHistogram${subSection}Description`);
+ expect(wrapper.length).toBe(1);
+ const description = wrapper.text();
+
+ switch(subSection) {
+ case 'TimeField':
+ expect(description).toEqual(defaultJob.dateHistogramField);
+ break;
+ case 'Interval':
+ expect(description).toEqual(defaultJob.dateHistogramInterval);
+ break;
+ case 'Timezone':
+ expect(description).toEqual(defaultJob.dateHistogramTimeZone);
+ break;
+ default:
+ // Should never get here... if it does a section is missing in the constant
+ throw(new Error('Should not get here. The constant DATE_HISTOGRAMS_SUBSECTIONS is probably missing a new subsection'));
+ }
+ });
+ });
+ });
+
+ describe('Stats section', () => {
+ const STATS_SUBSECTIONS = ['DocumentsProcessed', 'PagesProcessed', 'RollupsIndexed', 'TriggerCount'];
+
+ it('should have "Documents processed", "Pages processed", "Rollups indexed" and "Trigger count" subsections', () => {
+ const statsSubSections = STATS_SUBSECTIONS.reduce((subSections, subSection) => {
+ if (findTestSubject(`rollupJobDetailStats${subSection}Title`)) {
+ subSections.push(subSection);
+ }
+ return subSections;
+ }, []);
+ expect(statsSubSections).toEqual(STATS_SUBSECTIONS);
+ });
+
+ it('should set the correct job value for each of the subsection', () => {
+ STATS_SUBSECTIONS.forEach((subSection) => {
+ const wrapper = findTestSubject(`rollupJobDetailStats${subSection}Description`);
+ expect(wrapper.length).toBe(1);
+ const description = wrapper.text();
+
+ switch(subSection) {
+ case 'DocumentsProcessed':
+ expect(description).toEqual(defaultJob.documentsProcessed.toString());
+ break;
+ case 'PagesProcessed':
+ expect(description).toEqual(defaultJob.pagesProcessed.toString());
+ break;
+ case 'RollupsIndexed':
+ expect(description).toEqual(defaultJob.rollupsIndexed.toString());
+ break;
+ case 'TriggerCount':
+ expect(description).toEqual(defaultJob.triggerCount.toString());
+ break;
+ default:
+ // Should never get here... if it does a section is missing in the constant
+ throw(new Error('Should not get here. The constant STATS_SUBSECTIONS is probably missing a new subsection'));
+ }
+ });
+ });
+
+ it('should display the job status', () => {
+ const statsSection = findTestSubject('rollupJobDetailSummaryStatsSection');
+ expect(statsSection.length).toBe(1);
+ expect(defaultJob.status).toEqual('stopped'); // make sure status is Stopped
+ expect(statsSection.find('EuiHealth').text()).toEqual('Stopped');
+ });
+ });
+ });
+
+ describe('terms tab content', () => {
+ // Init testBed on the TERMS tab
+ const panelType = JOB_DETAILS_TAB_TERMS;
+ const { findTestSubject } = initTestBed({ panelType });
+ const tabContent = findTestSubject('rollupJobDetailTabContent');
+ const getRowsText = () => (
+ tabContent
+ .find('tr')
+ .map(row => row.text())
+ .slice(1) // we remove the first row as it is the table header
+ );
+ it('should list the Job terms fields', () => {
+ const rowsText = getRowsText();
+ const expected = defaultJob.terms.map(term => term.name);
+ expect(rowsText).toEqual(expected);
+ });
+ });
+
+ describe('histogram tab content', () => {
+ // Init testBed on the HISTOGRAM tab
+ const panelType = JOB_DETAILS_TAB_HISTOGRAM;
+ const { findTestSubject } = initTestBed({ panelType });
+ const tabContent = findTestSubject('rollupJobDetailTabContent');
+ const getRowsText = () => (
+ tabContent
+ .find('tr')
+ .map(row => row.text())
+ .slice(1) // we remove the first row as it is the table header
+ );
+
+ it('should list the Job histogram fields', () => {
+ const rowsText = getRowsText();
+ const expected = defaultJob.histogram.map(h => h.name);
+ expect(rowsText).toEqual(expected);
+ });
+ });
+
+ describe('metrics tab content', () => {
+ // Init testBed on the METRICS tab
+ const panelType = JOB_DETAILS_TAB_METRICS;
+ const { findTestSubject } = initTestBed({ panelType });
+ const tabContent = findTestSubject('rollupJobDetailTabContent');
+ const getRows = () => (
+ tabContent
+ .find('tr')
+ .slice(1)
+ );
+ it('should list the Job metrics fields and their types', () => {
+ const rows = getRows();
+
+ rows.forEach((row, i) => {
+ const metric = defaultJob.metrics[i];
+
+ row.find('td').forEach((cell, j) => {
+ if (j === 0) {
+ // field
+ expect(cell.text()).toEqual(metric.name);
+ } else if (j === 1) {
+ // types
+ expect(cell.text()).toEqual(metric.types.join(', '));
+ }
+ });
+ });
+ });
+ });
+
+ describe('JSON tab content', () => {
+ // Init testBed on the JSON tab
+ const panelType = JOB_DETAILS_TAB_JSON;
+ const { findTestSubject } = initTestBed({ panelType });
+ const tabContent = findTestSubject('rollupJobDetailTabContent');
+
+ it('should render the "EuiCodeEditor" with the job "json" data', () => {
+ const euiCodeEditor = tabContent.find('EuiCodeEditor');
+ expect(euiCodeEditor.length).toBeTruthy();
+ expect(JSON.parse(euiCodeEditor.props().value)).toEqual(defaultJob.json);
+ });
+ });
+ });
+});
diff --git a/x-pack/plugins/rollup/public/crud_app/sections/job_list/job_list.test.js b/x-pack/plugins/rollup/public/crud_app/sections/job_list/job_list.test.js
index 3c4ef49212469..f32cb5fe0918c 100644
--- a/x-pack/plugins/rollup/public/crud_app/sections/job_list/job_list.test.js
+++ b/x-pack/plugins/rollup/public/crud_app/sections/job_list/job_list.test.js
@@ -26,7 +26,7 @@ const defaultProps = {
loadJobs: () => {},
refreshJobs: () => {},
openDetailPanel: () => {},
- jobs: [],
+ hasJobs: false,
isLoading: false
};
@@ -40,14 +40,14 @@ describe('', () => {
});
it('should display a loading message when loading the jobs', () => {
- const { testSubjectExists } = initTestBed({ isLoading: true });
+ const { component, testSubjectExists } = initTestBed({ isLoading: true });
expect(testSubjectExists('jobListLoading')).toBeTruthy();
- expect(testSubjectExists('jobListTable')).toBeFalsy();
+ expect(component.find('JobTableUi').length).toBeFalsy();
});
it('should display the when there are jobs', () => {
- const { component, testSubjectExists } = initTestBed({ jobs: [{ foo: 'bar' }] });
+ const { component, testSubjectExists } = initTestBed({ hasJobs: true });
expect(testSubjectExists('jobListLoading')).toBeFalsy();
expect(component.find('JobTableUi').length).toBeTruthy();
diff --git a/x-pack/plugins/rollup/public/crud_app/sections/job_list/job_table/job_table.test.js b/x-pack/plugins/rollup/public/crud_app/sections/job_list/job_table/job_table.test.js
index d1867a485becd..11fe6cfc255bb 100644
--- a/x-pack/plugins/rollup/public/crud_app/sections/job_list/job_table/job_table.test.js
+++ b/x-pack/plugins/rollup/public/crud_app/sections/job_list/job_table/job_table.test.js
@@ -61,7 +61,7 @@ describe('', () => {
});
it('should set the correct job value in each row cell', () => {
- const fieldNames = [
+ const unformattedFields = [
'id',
'indexPattern',
'rollupIndex',
@@ -72,10 +72,9 @@ describe('', () => {
const job = jobs[0];
const getCellText = (field) => row.find(`[data-test-subj="jobTableCell-${field}"]`).hostNodes().text();
- // Simple fields
- fieldNames.forEach((fieldName) => {
- const cellText = getCellText(fieldName);
- expect(cellText).toEqual(job[fieldName]);
+ unformattedFields.forEach((field) => {
+ const cellText = getCellText(field);
+ expect(cellText).toEqual(job[field]);
});
// Status
@@ -84,16 +83,8 @@ describe('', () => {
expect(cellStatusText).toEqual('Stopped');
// Groups
- const expectedJobGroups = ['histogram', 'terms'].reduce((text, field) => {
- if (job[field].length) {
- return text
- ? `${text}, ${field}`
- : field.replace(/^\w/, char => char.toUpperCase());
- }
- return text;
- }, '');
const cellGroupsText = getCellText('groups');
- expect(cellGroupsText).toEqual(expectedJobGroups);
+ expect(cellGroupsText).toEqual('Histogram, terms');
// Metrics
const expectedJobMetrics = job.metrics.reduce((text, { name }) => (