diff --git a/src/legacy/core_plugins/kibana/public/discover/controllers/discover.js b/src/legacy/core_plugins/kibana/public/discover/controllers/discover.js index 9387428df3e251..0652a8f602be0e 100644 --- a/src/legacy/core_plugins/kibana/public/discover/controllers/discover.js +++ b/src/legacy/core_plugins/kibana/public/discover/controllers/discover.js @@ -54,7 +54,6 @@ import { migrateLegacyQuery } from 'ui/utils/migrate_legacy_query'; import { subscribeWithScope } from 'ui/utils/subscribe_with_scope'; import { getFilterGenerator } from 'ui/filter_manager'; import { SavedObjectsClientProvider } from 'ui/saved_objects'; -import { VisualizeLoaderProvider } from 'ui/visualize/loader/visualize_loader'; import { recentlyAccessed } from 'ui/persisted_log'; import { getDocLink } from 'ui/documentation_links'; import '../components/fetch_error'; @@ -195,8 +194,6 @@ function discoverController( localStorage, uiCapabilities ) { - const visualizeLoader = Private(VisualizeLoaderProvider); - let visualizeHandler; const Vis = Private(VisProvider); const responseHandler = vislibSeriesResponseHandlerProvider().handler; const getUnhashableStates = Private(getUnhashableStatesProvider); @@ -213,6 +210,13 @@ function discoverController( timefilter.disableTimeRangeSelector(); timefilter.disableAutoRefreshSelector(); + $scope.timefilterUpdateHandler = (ranges) => { + timefilter.setTime({ + from: moment(ranges.from).toISOString(), + to: moment(ranges.to).toISOString(), + mode: 'absolute', + }); + }; $scope.getDocLink = getDocLink; $scope.intervalOptions = intervalOptions; @@ -793,15 +797,7 @@ function discoverController( .resolve(buildVislibDimensions($scope.vis, { timeRange: $scope.timeRange, searchSource: $scope.searchSource })) .then(resp => responseHandler(tabifiedData, resp)) .then(resp => { - visualizeHandler.render({ - as: 'visualization', - value: { - visType: $scope.vis.type.name, - visData: resp, - visConfig: $scope.vis.params, - params: {}, - } - }); + $scope.histogramData = resp; }); } @@ -1047,13 +1043,6 @@ function discoverController( $scope.searchSource.setField('aggs', function () { return $scope.vis.getAggConfig().toDsl(); }); - - $timeout(async () => { - const visEl = $element.find('#discoverHistogram')[0]; - visualizeHandler = await visualizeLoader.embedVisualizationWithSavedObject(visEl, visSavedObject, { - autoFetch: false, - }); - }); } function resolveIndexPatternLoading() { diff --git a/src/legacy/core_plugins/kibana/public/discover/directives/_histogram.scss b/src/legacy/core_plugins/kibana/public/discover/directives/_histogram.scss new file mode 100644 index 00000000000000..948f438eea5423 --- /dev/null +++ b/src/legacy/core_plugins/kibana/public/discover/directives/_histogram.scss @@ -0,0 +1,4 @@ +.dscHistogram__header--partial { + font-weight: $euiFontWeightRegular; + min-width: $euiSize * 12; +} diff --git a/src/legacy/core_plugins/kibana/public/discover/directives/_index.scss b/src/legacy/core_plugins/kibana/public/discover/directives/_index.scss index 8d092c11a4e1ef..c65243d99c8f49 100644 --- a/src/legacy/core_plugins/kibana/public/discover/directives/_index.scss +++ b/src/legacy/core_plugins/kibana/public/discover/directives/_index.scss @@ -1 +1,2 @@ @import 'no_results'; +@import 'histogram'; \ No newline at end of file diff --git a/src/legacy/core_plugins/kibana/public/discover/directives/histogram.tsx b/src/legacy/core_plugins/kibana/public/discover/directives/histogram.tsx new file mode 100644 index 00000000000000..e387355af69556 --- /dev/null +++ b/src/legacy/core_plugins/kibana/public/discover/directives/histogram.tsx @@ -0,0 +1,258 @@ +/* + * 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 { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiSpacer } from '@elastic/eui'; +import moment from 'moment-timezone'; +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import lightEuiTheme from '@elastic/eui/dist/eui_theme_light.json'; +import darkEuiTheme from '@elastic/eui/dist/eui_theme_dark.json'; + +import { + AnnotationDomainTypes, + Axis, + Chart, + HistogramBarSeries, + GeometryValue, + getAnnotationId, + getAxisId, + getSpecId, + LineAnnotation, + Position, + ScaleType, + Settings, + RectAnnotation, + TooltipValue, + TooltipType, +} from '@elastic/charts'; + +import { i18n } from '@kbn/i18n'; + +import { getChartTheme } from 'ui/elastic_charts'; +import chrome from 'ui/chrome'; +// @ts-ignore: path dynamic for kibana +import { timezoneProvider } from 'ui/vis/lib/timezone'; + +export interface DiscoverHistogramProps { + chartData: any; + timefilterUpdateHandler: (ranges: { from: number; to: number }) => void; +} + +export class DiscoverHistogram extends Component { + public static propTypes = { + chartData: PropTypes.object, + timefilterUpdateHandler: PropTypes.func, + }; + + public onBrushEnd = (min: number, max: number) => { + const range = { + from: min, + to: max, + }; + + this.props.timefilterUpdateHandler(range); + }; + + public onElementClick = (xInterval: number) => (elementData: GeometryValue[]) => { + const startRange = elementData[0].x; + + const range = { + from: startRange, + to: startRange + xInterval, + }; + + this.props.timefilterUpdateHandler(range); + }; + + public formatXValue = (val: string) => { + const xAxisFormat = this.props.chartData.xAxisFormat.params.pattern; + + return moment(val).format(xAxisFormat); + }; + + public renderBarTooltip = (xInterval: number, domainStart: number, domainEnd: number) => ( + headerData: TooltipValue + ): JSX.Element | string => { + const headerDataValue = headerData.value; + const formattedValue = this.formatXValue(headerDataValue); + + const partialDataText = i18n.translate('kbn.discover.histogram.partialData.bucketTooltipText', { + defaultMessage: + 'The selected time range does not include this entire bucket, it may contain partial data.', + }); + + if (headerDataValue < domainStart || headerDataValue + xInterval > domainEnd) { + return ( + + + + + + {partialDataText} + + +

{formattedValue}

+
+ ); + } + + return formattedValue; + }; + + public render() { + const uiSettings = chrome.getUiSettingsClient(); + const timeZone = timezoneProvider(uiSettings)(); + const { chartData } = this.props; + + if (!chartData || !chartData.series[0]) { + return null; + } + + const data = chartData.series[0].values; + + /** + * Deprecation: [interval] on [date_histogram] is deprecated, use [fixed_interval] or [calendar_interval]. + * see https://github.com/elastic/kibana/issues/27410 + * TODO: Once the Discover query has been update, we should change the below to use the new field + */ + const xInterval = chartData.ordered.interval; + + const xValues = chartData.xAxisOrderedValues; + const lastXValue = xValues[xValues.length - 1]; + + const domain = chartData.ordered; + const domainStart = domain.min.valueOf(); + const domainEnd = domain.max.valueOf(); + + const domainMin = data[0].x > domainStart ? domainStart : data[0].x; + const domainMax = domainEnd - xInterval > lastXValue ? domainEnd - xInterval : lastXValue; + + const xDomain = { + min: domainMin, + max: domainMax, + minInterval: xInterval, + }; + + // Domain end of 'now' will be milliseconds behind current time, so we extend time by 1 minute and check if + // the annotation is within this range; if so, the line annotation uses the domainEnd as its value + const now = moment(); + const isAnnotationAtEdge = + moment(domainEnd) + .add(60000) + .isAfter(now) && now.isAfter(domainEnd); + const lineAnnotationValue = isAnnotationAtEdge ? domainEnd : now; + + const lineAnnotationData = [ + { + dataValue: lineAnnotationValue, + }, + ]; + const isDarkMode = uiSettings.get('theme:darkMode'); + + const lineAnnotationStyle = { + line: { + strokeWidth: 2, + stroke: isDarkMode ? darkEuiTheme.euiColorDanger : lightEuiTheme.euiColorDanger, + opacity: 0.7, + }, + }; + + const rectAnnotations = []; + if (domainStart !== domainMin) { + rectAnnotations.push({ + coordinates: { + x1: domainStart, + }, + }); + } + if (domainEnd !== domainMax) { + rectAnnotations.push({ + coordinates: { + x0: domainEnd, + }, + }); + } + + const rectAnnotationStyle = { + stroke: isDarkMode ? darkEuiTheme.euiColorLightShade : lightEuiTheme.euiColorDarkShade, + strokeWidth: 0, + opacity: isDarkMode ? 0.6 : 0.2, + fill: isDarkMode ? darkEuiTheme.euiColorLightShade : lightEuiTheme.euiColorDarkShade, + }; + + const tooltipProps = { + headerFormatter: this.renderBarTooltip(xInterval, domainStart, domainEnd), + type: TooltipType.VerticalCursor, + }; + + return ( + + + + + + + + + ); + } +} diff --git a/src/legacy/core_plugins/kibana/public/discover/directives/index.js b/src/legacy/core_plugins/kibana/public/discover/directives/index.js index d13448bbf9c8a1..a6f0ead4f73657 100644 --- a/src/legacy/core_plugins/kibana/public/discover/directives/index.js +++ b/src/legacy/core_plugins/kibana/public/discover/directives/index.js @@ -20,14 +20,10 @@ import 'ngreact'; import { wrapInI18nContext } from 'ui/i18n'; import { uiModules } from 'ui/modules'; - import { DiscoverNoResults } from './no_results'; - import { DiscoverUninitialized } from './uninitialized'; - import { DiscoverUnsupportedIndexPattern } from './unsupported_index_pattern'; - -import './timechart'; +import { DiscoverHistogram } from './histogram'; const app = uiModules.get('apps/discover', ['react']); @@ -42,3 +38,5 @@ app.directive('discoverUninitialized', reactDirective => app.directive('discoverUnsupportedIndexPattern', reactDirective => reactDirective(wrapInI18nContext(DiscoverUnsupportedIndexPattern), ['unsupportedType']) ); + +app.directive('discoverHistogram', reactDirective => reactDirective(DiscoverHistogram)); diff --git a/src/legacy/core_plugins/kibana/public/discover/index.html b/src/legacy/core_plugins/kibana/public/discover/index.html index 980b3fefc6dd88..ae6bf340295fc7 100644 --- a/src/legacy/core_plugins/kibana/public/discover/index.html +++ b/src/legacy/core_plugins/kibana/public/discover/index.html @@ -162,11 +162,13 @@ -
-
+ ng-show="vis && rows.length !== 0" + chart-data="histogramData" + timefilter-update-handler="timefilterUpdateHandler" + watch-depth="reference" + >
{ - await verifyChartData(expectedBarChartData); - }); - }); - - it('should show correct data for chart interval Weekly', async function () { - const chartInterval = 'Weekly'; - const expectedBarChartData = [4757, 9247]; - - await PageObjects.discover.setChartInterval(chartInterval); - await retry.try(async () => { - await verifyChartData(expectedBarChartData); - }); - }); - - it('browser back button should show previous interval Daily', async function () { - const expectedChartInterval = 'Daily'; - const expectedBarChartData = [4757, 4614, 4633]; - - await browser.goBack(); - await retry.try(async function tryingForTime() { - const actualInterval = await PageObjects.discover.getChartInterval(); - expect(actualInterval).to.be(expectedChartInterval); - }); - await verifyChartData(expectedBarChartData); - }); - - it('should show correct data for chart interval Monthly', async function () { - const chartInterval = 'Monthly'; - const expectedBarChartData = [13129]; - - await PageObjects.discover.setChartInterval(chartInterval); - await verifyChartData(expectedBarChartData); - }); - - it('should show correct data for chart interval Yearly', async function () { - const chartInterval = 'Yearly'; - const expectedBarChartData = [13129]; - - await PageObjects.discover.setChartInterval(chartInterval); - await verifyChartData(expectedBarChartData); - }); - - it('should show correct data for chart interval Auto', async function () { - const chartInterval = 'Auto'; - const expectedBarChartData = [ - 35, - 189, - 694, - 1347, - 1285, - 704, - 176, - 29, - 39, - 189, - 640, - 1276, - 1327, - 663, - 166, - 25, - 30, - 164, - 663, - 1320, - 1270, - 681, - 188, - 27, - ]; - - await PageObjects.discover.setChartInterval(chartInterval); - await verifyChartData(expectedBarChartData); - }); - it('should show Auto chart interval', async function () { const expectedChartInterval = 'Auto'; @@ -344,42 +130,6 @@ export default function ({ getService, getPageObjects }) { const isVisible = await PageObjects.discover.hasNoResults(); expect(isVisible).to.be(false); }); - - async function verifyChartData(expectedBarChartData) { - await retry.try(async function tryingForTime() { - const paths = await PageObjects.discover.getBarChartData(); - // the largest bars are over 100 pixels high so this is less than 1% tolerance - const barHeightTolerance = 1; - let stringResults = ''; - let hasFailure = false; - for (let y = 0; y < expectedBarChartData.length; y++) { - stringResults += - y + - ': expected = ' + - expectedBarChartData[y] + - ', actual = ' + - paths[y] + - ', Pass = ' + - (Math.abs(expectedBarChartData[y] - paths[y]) < - barHeightTolerance) + - '\n'; - if ( - Math.abs(expectedBarChartData[y] - paths[y]) > barHeightTolerance - ) { - hasFailure = true; - } - } - if (hasFailure) { - log.debug(stringResults); - log.debug(paths); - } - for (let x = 0; x < expectedBarChartData.length; x++) { - expect( - Math.abs(expectedBarChartData[x] - paths[x]) < barHeightTolerance - ).to.be.ok(); - } - }); - } }); describe('query #2, which has an empty time range', () => { @@ -437,7 +187,8 @@ export default function ({ getService, getPageObjects }) { }); describe('time zone switch', () => { - it('should show bars in the correct time zone after switching', async function () { + // skipping this until we get an elastic-chart alternative to check the ticks value + it.skip('should show ticks in the correct time zone after switching', async function () { await kibanaServer.uiSettings.replace({ 'dateFormat:tz': 'America/Phoenix' }); await browser.refresh(); await PageObjects.header.awaitKibanaChrome(); @@ -462,6 +213,16 @@ export default function ({ getService, getPageObjects }) { } }); }); + it('should show bars in the correct time zone after switching', async function () { + await kibanaServer.uiSettings.replace({ 'dateFormat:tz': 'America/Phoenix' }); + await browser.refresh(); + await PageObjects.header.awaitKibanaChrome(); + await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); + + log.debug('check that the newest doc timestamp is now -7 hours from the UTC time in the first test'); + const rowData = await PageObjects.discover.getDocTableIndex(1); + expect(rowData.startsWith('Sep 22, 2015 @ 16:50:13.253')).to.be.ok(); + }); }); }); } diff --git a/test/functional/apps/management/_scripted_fields.js b/test/functional/apps/management/_scripted_fields.js index ec3941264450de..32d410eb240408 100644 --- a/test/functional/apps/management/_scripted_fields.js +++ b/test/functional/apps/management/_scripted_fields.js @@ -129,13 +129,13 @@ export default function ({ getService, getPageObjects }) { const toTime = '2015-09-18 18:31:44.000'; await PageObjects.common.navigateToApp('discover'); await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); - await PageObjects.visualize.waitForVisualization(); + await PageObjects.discover.clickFieldListItem(scriptedPainlessFieldName); await retry.try(async function () { await PageObjects.discover.clickFieldListItemAdd(scriptedPainlessFieldName); }); await PageObjects.header.waitUntilLoadingHasFinished(); - await PageObjects.visualize.waitForVisualization(); + await retry.try(async function () { const rowData = await PageObjects.discover.getDocTableIndex(1); expect(rowData).to.be('Sep 18, 2015 @ 18:20:57.916\n18'); @@ -147,7 +147,7 @@ export default function ({ getService, getPageObjects }) { await log.debug('filter by the first value (14) in the expanded scripted field list'); await PageObjects.discover.clickFieldListPlusFilter(scriptedPainlessFieldName, '14'); await PageObjects.header.waitUntilLoadingHasFinished(); - await PageObjects.visualize.waitForVisualization(); + await retry.try(async function () { expect(await PageObjects.discover.getHitCount()).to.be('31'); }); @@ -161,7 +161,7 @@ export default function ({ getService, getPageObjects }) { await filterBar.removeAllFilters(); await PageObjects.discover.clickFieldListItemVisualize(scriptedPainlessFieldName); await PageObjects.header.waitUntilLoadingHasFinished(); - await PageObjects.visualize.waitForVisualization(); + await inspector.open(); await inspector.setTablePageSize(50); await inspector.expectTableData(expectedChartValues); @@ -191,13 +191,13 @@ export default function ({ getService, getPageObjects }) { const toTime = '2015-09-18 18:31:44.000'; await PageObjects.common.navigateToApp('discover'); await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); - await PageObjects.visualize.waitForVisualization(); + await PageObjects.discover.clickFieldListItem(scriptedPainlessFieldName2); await retry.try(async function () { await PageObjects.discover.clickFieldListItemAdd(scriptedPainlessFieldName2); }); await PageObjects.header.waitUntilLoadingHasFinished(); - await PageObjects.visualize.waitForVisualization(); + await retry.try(async function () { const rowData = await PageObjects.discover.getDocTableIndex(1); expect(rowData).to.be('Sep 18, 2015 @ 18:20:57.916\ngood'); @@ -210,7 +210,7 @@ export default function ({ getService, getPageObjects }) { await log.debug('filter by "bad" in the expanded scripted field list'); await PageObjects.discover.clickFieldListPlusFilter(scriptedPainlessFieldName2, 'bad'); await PageObjects.header.waitUntilLoadingHasFinished(); - await PageObjects.visualize.waitForVisualization(); + await retry.try(async function () { expect(await PageObjects.discover.getHitCount()).to.be('27'); }); @@ -220,7 +220,6 @@ export default function ({ getService, getPageObjects }) { it('should visualize scripted field in vertical bar chart', async function () { await PageObjects.discover.clickFieldListItemVisualize(scriptedPainlessFieldName2); await PageObjects.header.waitUntilLoadingHasFinished(); - await PageObjects.visualize.waitForVisualization(); await inspector.open(); await inspector.expectTableData([ ['good', '359'], @@ -252,13 +251,13 @@ export default function ({ getService, getPageObjects }) { const toTime = '2015-09-18 18:31:44.000'; await PageObjects.common.navigateToApp('discover'); await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); - await PageObjects.visualize.waitForVisualization(); + await PageObjects.discover.clickFieldListItem(scriptedPainlessFieldName2); await retry.try(async function () { await PageObjects.discover.clickFieldListItemAdd(scriptedPainlessFieldName2); }); await PageObjects.header.waitUntilLoadingHasFinished(); - await PageObjects.visualize.waitForVisualization(); + await retry.try(async function () { const rowData = await PageObjects.discover.getDocTableIndex(1); expect(rowData).to.be('Sep 18, 2015 @ 18:20:57.916\ntrue'); @@ -271,7 +270,7 @@ export default function ({ getService, getPageObjects }) { await log.debug('filter by "true" in the expanded scripted field list'); await PageObjects.discover.clickFieldListPlusFilter(scriptedPainlessFieldName2, 'true'); await PageObjects.header.waitUntilLoadingHasFinished(); - await PageObjects.visualize.waitForVisualization(); + await retry.try(async function () { expect(await PageObjects.discover.getHitCount()).to.be('359'); }); @@ -281,7 +280,6 @@ export default function ({ getService, getPageObjects }) { it('should visualize scripted field in vertical bar chart', async function () { await PageObjects.discover.clickFieldListItemVisualize(scriptedPainlessFieldName2); await PageObjects.header.waitUntilLoadingHasFinished(); - await PageObjects.visualize.waitForVisualization(); await inspector.open(); await inspector.expectTableData([ ['true', '359'], @@ -314,13 +312,13 @@ export default function ({ getService, getPageObjects }) { const toTime = '2015-09-18 07:00:00.000'; await PageObjects.common.navigateToApp('discover'); await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); - await PageObjects.visualize.waitForVisualization(); + await PageObjects.discover.clickFieldListItem(scriptedPainlessFieldName2); await retry.try(async function () { await PageObjects.discover.clickFieldListItemAdd(scriptedPainlessFieldName2); }); await PageObjects.header.waitUntilLoadingHasFinished(); - await PageObjects.visualize.waitForVisualization(); + await retry.try(async function () { const rowData = await PageObjects.discover.getDocTableIndex(1); expect(rowData).to.be('Sep 18, 2015 @ 06:52:55.953\n2015-09-18 07:00'); @@ -332,7 +330,7 @@ export default function ({ getService, getPageObjects }) { await log.debug('filter by "2015-09-17 23:00" in the expanded scripted field list'); await PageObjects.discover.clickFieldListPlusFilter(scriptedPainlessFieldName2, '2015-09-17 23:00'); await PageObjects.header.waitUntilLoadingHasFinished(); - await PageObjects.visualize.waitForVisualization(); + await retry.try(async function () { expect(await PageObjects.discover.getHitCount()).to.be('1'); }); @@ -342,7 +340,6 @@ export default function ({ getService, getPageObjects }) { it('should visualize scripted field in vertical bar chart', async function () { await PageObjects.discover.clickFieldListItemVisualize(scriptedPainlessFieldName2); await PageObjects.header.waitUntilLoadingHasFinished(); - await PageObjects.visualize.waitForVisualization(); await inspector.open(); await inspector.setTablePageSize(50); await inspector.expectTableData([ diff --git a/test/functional/page_objects/discover_page.js b/test/functional/page_objects/discover_page.js index dfe8dc1071d46c..52b4c8d931ae21 100644 --- a/test/functional/page_objects/discover_page.js +++ b/test/functional/page_objects/discover_page.js @@ -116,16 +116,20 @@ export function DiscoverPageProvider({ getService, getPageObjects }) { await testSubjects.click('discoverOpenButton'); } - async clickHistogramBar(i) { - const bars = await find.allByCssSelector(`.series.histogram rect`); - await bars[i].click(); + async clickHistogramBar() { + const el = await find.byCssSelector('.echChart canvas:last-of-type'); + + await browser.getActions() + .move({ x: 200, y: 20, origin: el._webElement }) + .click() + .perform(); } - async brushHistogram(from, to) { - const bars = await find.allByCssSelector('.series.histogram rect'); + async brushHistogram() { + const el = await find.byCssSelector('.echChart canvas:last-of-type'); await browser.dragAndDrop( - { location: bars[from], offset: { x: 0, y: -5 } }, - { location: bars[to], offset: { x: 0, y: -5 } } + { location: el, offset: { x: 200, y: 20 } }, + { location: el, offset: { x: 400, y: 30 } } ); } @@ -133,12 +137,6 @@ export function DiscoverPageProvider({ getService, getPageObjects }) { return await globalNav.getLastBreadcrumb(); } - async getBarChartXTicks() { - const xAxis = await find.byCssSelector('.x.axis.CategoryAxis-1'); - const $ = await xAxis.parseDomContent(); - return $('.tick > text').toArray().map(tick => $(tick).text().trim()); - } - async getBarChartData() { let yAxisLabel = 0; diff --git a/test/visual_regression/config.ts b/test/visual_regression/config.ts index 74f283f74683a8..77450b517dcc6d 100644 --- a/test/visual_regression/config.ts +++ b/test/visual_regression/config.ts @@ -26,7 +26,7 @@ export default async function({ readConfigFile }: FtrConfigProviderContext) { return { ...functionalConfig.getAll(), - testFiles: [require.resolve('./tests/console_app')], + testFiles: [require.resolve('./tests/console_app'), require.resolve('./tests/discover')], services, diff --git a/test/visual_regression/services/visual_testing/visual_testing.ts b/test/visual_regression/services/visual_testing/visual_testing.ts index 2b05f666a3500b..210de4c714d5cb 100644 --- a/test/visual_regression/services/visual_testing/visual_testing.ts +++ b/test/visual_regression/services/visual_testing/visual_testing.ts @@ -27,15 +27,15 @@ import { FtrProviderContext } from '../../ftr_provider_context'; // @ts-ignore internal js that is passed to the browser as is import { takePercySnapshot, takePercySnapshotWithAgent } from './take_percy_snapshot'; +export const DEFAULT_OPTIONS = { + widths: [1200], +}; + export async function VisualTestingProvider({ getService }: FtrProviderContext) { const browser = getService('browser'); const log = getService('log'); const lifecycle = getService('lifecycle'); - const DEFAULT_OPTIONS = { - widths: [1200], - }; - let currentTest: Test | undefined; lifecycle.on('beforeEachTest', (test: Test) => { currentTest = test; diff --git a/test/visual_regression/tests/discover/chart_visualization.js b/test/visual_regression/tests/discover/chart_visualization.js new file mode 100644 index 00000000000000..ca3def70627d9a --- /dev/null +++ b/test/visual_regression/tests/discover/chart_visualization.js @@ -0,0 +1,123 @@ +/* + * 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 expect from '@kbn/expect'; + +export default function ({ getService, getPageObjects }) { + const log = getService('log'); + const retry = getService('retry'); + const esArchiver = getService('esArchiver'); + const browser = getService('browser'); + const kibanaServer = getService('kibanaServer'); + const PageObjects = getPageObjects(['common', 'discover', 'header', 'timePicker']); + const visualTesting = getService('visualTesting'); + const defaultSettings = { + defaultIndex: 'logstash-*', + }; + + describe('discover', function describeIndexTests() { + const fromTime = '2015-09-19 06:31:44.000'; + const toTime = '2015-09-23 18:31:44.000'; + + before(async function () { + log.debug('load kibana index with default index pattern'); + await esArchiver.load('discover'); + + // and load a set of makelogs data + await esArchiver.loadIfNeeded('logstash_functional'); + await kibanaServer.uiSettings.replace(defaultSettings); + log.debug('discover'); + await PageObjects.common.navigateToApp('discover'); + await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); + }); + + describe('query', function () { + this.tags(['skipFirefox']); + + it('should show bars in the correct time zone', async function () { + await PageObjects.header.awaitGlobalLoadingIndicatorHidden(); + await visualTesting.snapshot(); + }); + + it('should show correct data for chart interval Hourly', async function () { + await PageObjects.header.awaitGlobalLoadingIndicatorHidden(); + await PageObjects.discover.setChartInterval('Hourly'); + await visualTesting.snapshot(); + }); + + it('should show correct data for chart interval Daily', async function () { + await PageObjects.header.awaitGlobalLoadingIndicatorHidden(); + await PageObjects.discover.setChartInterval('Daily'); + await retry.try(async () => { + await visualTesting.snapshot(); + }); + }); + + it('should show correct data for chart interval Weekly', async function () { + await PageObjects.header.awaitGlobalLoadingIndicatorHidden(); + await PageObjects.discover.setChartInterval('Weekly'); + await retry.try(async () => { + await visualTesting.snapshot(); + }); + }); + + it('browser back button should show previous interval Daily', async function () { + await browser.goBack(); + await retry.try(async function tryingForTime() { + const actualInterval = await PageObjects.discover.getChartInterval(); + expect(actualInterval).to.be('Daily'); + }); + await PageObjects.header.awaitGlobalLoadingIndicatorHidden(); + await visualTesting.snapshot(); + }); + + it('should show correct data for chart interval Monthly', async function () { + await PageObjects.header.awaitGlobalLoadingIndicatorHidden(); + await PageObjects.discover.setChartInterval('Monthly'); + await visualTesting.snapshot(); + }); + + it('should show correct data for chart interval Yearly', async function () { + await PageObjects.header.awaitGlobalLoadingIndicatorHidden(); + await PageObjects.discover.setChartInterval('Yearly'); + await visualTesting.snapshot(); + }); + + it('should show correct data for chart interval Auto', async function () { + await PageObjects.header.awaitGlobalLoadingIndicatorHidden(); + await PageObjects.discover.setChartInterval('Auto'); + await visualTesting.snapshot(); + }); + }); + + describe('time zone switch', () => { + it('should show bars in the correct time zone after switching', async function () { + await kibanaServer.uiSettings.replace({ 'dateFormat:tz': 'America/Phoenix' }); + await browser.refresh(); + await PageObjects.header.awaitKibanaChrome(); + await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); + await PageObjects.header.awaitGlobalLoadingIndicatorHidden(); + await retry.try(async function () { + await visualTesting.snapshot(); + }); + }); + + }); + }); +} diff --git a/test/visual_regression/tests/discover/index.js b/test/visual_regression/tests/discover/index.js new file mode 100644 index 00000000000000..ba44fb12eef703 --- /dev/null +++ b/test/visual_regression/tests/discover/index.js @@ -0,0 +1,42 @@ +/* +* 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 { DEFAULT_OPTIONS } from '../../services/visual_testing/visual_testing'; + +// Width must be the same as visual_testing or canvas image widths will get skewed +const [SCREEN_WIDTH] = DEFAULT_OPTIONS.widths || []; + +export default function ({ getService, loadTestFile }) { + const esArchiver = getService('esArchiver'); + const browser = getService('browser'); + + describe('discover app', function () { + this.tags('ciGroup6'); + + before(function () { + return browser.setWindowSize(SCREEN_WIDTH, 1000); + }); + + after(function unloadMakelogs() { + return esArchiver.unload('logstash_functional'); + }); + + loadTestFile(require.resolve('./chart_visualization')); + }); +}