Add functional tests for visualize loader API (#22595) (#22649)

* Initial visualize loader functional tests

* Extend plugin test README

* Add temporary tz work around

* Switch to Australia/North timezone

* Add filtering tests

* Add all tests

* Remove unneeded uiExports

* Improve explanation

* Add saved object test, add retry
This commit is contained in:
Tim Roes 2018-09-04 15:09:57 +02:00 committed by GitHub
parent c9f753155e
commit 9f37b1fe51
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 996 additions and 0 deletions

View file

@ -62,6 +62,11 @@ class VisualizeLoader {
* In most of the cases you will need this method, since it allows you to specify
* filters, handlers, queries, etc. on the savedObject before rendering.
*
* We do not encourage you to use this method, since it will most likely be changed
* or removed in a future version of Kibana. Rather embed a visualization by its id
* via the {@link #embedVisualizationWithId} method.
*
* @deprecated You should rather embed by id, since this method will be removed in the future.
* @param element The DOM element to render the visualization into.
* You can alternatively pass a jQuery element instead.
* @param savedObj The savedObject as it could be retrieved by the
@ -106,6 +111,8 @@ class VisualizeLoader {
element.className = 'visualize';
element.setAttribute('data-test-subj', 'visualizationLoader');
container.appendChild(element);
// We need the container to have display: flex so visualization will render correctly
container.style.display = 'flex';
// If params specified cssClass, we will set this to the element.
if (params.cssClass) {

View file

@ -53,6 +53,7 @@ import {
ComboBoxProvider,
EmbeddingProvider,
RenderableProvider,
TableProvider,
} from './services';
export default async function ({ readConfigFile }) {
@ -111,6 +112,7 @@ export default async function ({ readConfigFile }) {
comboBox: ComboBoxProvider,
embedding: EmbeddingProvider,
renderable: RenderableProvider,
table: TableProvider,
},
servers: commonConfig.get('servers'),

View file

@ -0,0 +1,246 @@
{
"type": "index",
"value": {
"index": ".kibana",
"settings": {
"index": {
"number_of_shards": "1",
"number_of_replicas": "1"
}
},
"mappings": {
"doc": {
"properties": {
"type": {
"type": "keyword"
},
"server": {
"dynamic": "strict",
"properties": {
"uuid": {
"type": "keyword"
}
}
},
"url": {
"dynamic": "strict",
"properties": {
"accessCount": {
"type": "long"
},
"accessDate": {
"type": "date"
},
"createDate": {
"type": "date"
},
"url": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 2048
}
}
}
}
},
"search": {
"dynamic": "strict",
"properties": {
"columns": {
"type": "keyword"
},
"description": {
"type": "text"
},
"hits": {
"type": "integer"
},
"kibanaSavedObjectMeta": {
"properties": {
"searchSourceJSON": {
"type": "text"
}
}
},
"sort": {
"type": "keyword"
},
"title": {
"type": "text"
},
"version": {
"type": "integer"
}
}
},
"visualization": {
"dynamic": "strict",
"properties": {
"description": {
"type": "text"
},
"kibanaSavedObjectMeta": {
"properties": {
"searchSourceJSON": {
"type": "text"
}
}
},
"savedSearchId": {
"type": "keyword"
},
"title": {
"type": "text"
},
"uiStateJSON": {
"type": "text"
},
"version": {
"type": "integer"
},
"visState": {
"type": "text"
}
}
},
"index-pattern": {
"dynamic": "strict",
"properties": {
"fieldFormatMap": {
"type": "text"
},
"fields": {
"type": "text"
},
"intervalName": {
"type": "keyword"
},
"notExpandable": {
"type": "boolean"
},
"sourceFilters": {
"type": "text"
},
"timeFieldName": {
"type": "keyword"
},
"title": {
"type": "text"
}
}
},
"config": {
"dynamic": "true",
"properties": {
"buildNum": {
"type": "keyword"
}
}
},
"dashboard": {
"dynamic": "strict",
"properties": {
"description": {
"type": "text"
},
"hits": {
"type": "integer"
},
"kibanaSavedObjectMeta": {
"properties": {
"searchSourceJSON": {
"type": "text"
}
}
},
"optionsJSON": {
"type": "text"
},
"panelsJSON": {
"type": "text"
},
"refreshInterval": {
"properties": {
"display": {
"type": "keyword"
},
"pause": {
"type": "boolean"
},
"section": {
"type": "integer"
},
"value": {
"type": "integer"
}
}
},
"timeFrom": {
"type": "keyword"
},
"timeRestore": {
"type": "boolean"
},
"timeTo": {
"type": "keyword"
},
"title": {
"type": "text"
},
"uiStateJSON": {
"type": "text"
},
"version": {
"type": "integer"
}
}
},
"timelion-sheet": {
"dynamic": "strict",
"properties": {
"description": {
"type": "text"
},
"hits": {
"type": "integer"
},
"kibanaSavedObjectMeta": {
"properties": {
"searchSourceJSON": {
"type": "text"
}
}
},
"timelion_chart_height": {
"type": "integer"
},
"timelion_columns": {
"type": "integer"
},
"timelion_interval": {
"type": "keyword"
},
"timelion_other_interval": {
"type": "keyword"
},
"timelion_rows": {
"type": "integer"
},
"timelion_sheet": {
"type": "text"
},
"title": {
"type": "text"
},
"version": {
"type": "integer"
}
}
}
}
}
}
}
}

View file

@ -30,5 +30,6 @@ export { FlyoutProvider } from './flyout';
export { EmbeddingProvider } from './embedding';
export { ComboBoxProvider } from './combo_box';
export { RenderableProvider } from './renderable';
export { TableProvider } from './table';
export * from './dashboard';

View file

@ -0,0 +1,39 @@
/*
* 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.
*/
export function TableProvider({ getService }) {
const testSubjects = getService('testSubjects');
// const retry = getService('retry');
class Table {
async getDataFromTestSubj(testSubj) {
const table = await testSubjects.find(testSubj);
// Convert the data into a nested array format:
// [ [cell1_in_row1, cell2_in_row1], [cell1_in_row2, cell2_in_row2] ]
const rows = await table.findAllByTagName('tr');
return await Promise.all(rows.map(async row => {
const cells = await row.findAllByTagName('td');
return await Promise.all(cells.map(async cell => cell.getVisibleText()));
}));
}
}
return new Table();
}

View file

@ -21,3 +21,12 @@ node scripts/functional_tests_server.js --config test/plugin_functional/config.j
# Start a test run
node scripts/functional_test_runner.js --config test/plugin_functional/config.js
```
## Run Kibana with a test plugin
In case you want to start Kibana with one of the test plugins (e.g. for developing the
test plugin), you can just run:
```
yarn start --plugin-path=test/plugin_functional/plugins/<plugin_folder>
```

View file

@ -30,6 +30,7 @@ export default async function ({ readConfigFile }) {
return {
testFiles: [
require.resolve('./test_suites/app_plugins'),
require.resolve('./test_suites/embedding_visualizations'),
require.resolve('./test_suites/panel_actions'),
],
services: functionalConfig.get('services'),

View file

@ -0,0 +1,39 @@
/*
* 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.
*/
export default function (kibana) {
return new kibana.Plugin({
uiExports: {
app: {
title: 'Embedding Vis',
description: 'This is a sample plugin to test embedding of visualizations',
main: 'plugins/visualize_embedding/app',
}
},
init(server) {
// The following lines copy over some configuration variables from Kibana
// to this plugin. This will be needed when embedding visualizations, so that e.g.
// region map is able to get its configuration.
server.injectUiAppVars('visualize_embedding', async () => {
return await server.getInjectedUiAppVars('kibana');
});
}
});
}

View file

@ -0,0 +1,4 @@
{
"name": "visualize_embedding",
"version": "kibana"
}

View file

@ -0,0 +1,95 @@
/*
* 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 React from 'react';
import { render, unmountComponentAtNode } from 'react-dom';
import { uiModules } from 'ui/modules';
import chrome from 'ui/chrome';
// This is required so some default styles and required scripts/Angular modules are loaded,
// or the timezone setting is correctly applied.
import 'ui/autoload/all';
// These are all the required uiExports you need to import in case you want to embed visualizations.
import 'uiExports/visTypes';
import 'uiExports/visResponseHandlers';
import 'uiExports/visRequestHandlers';
import 'uiExports/visEditorTypes';
import 'uiExports/visualize';
import 'uiExports/savedObjectTypes';
import 'uiExports/fieldFormats';
import 'uiExports/search';
// ----------- TODO Remove once https://github.com/elastic/kibana/pull/22623 is merged
import moment from 'moment-timezone';
function setDefaultTimezone(tz) {
moment.tz.setDefault(tz);
}
function setStartDayOfWeek(day) {
const dow = moment.weekdays().indexOf(day);
moment.updateLocale(moment.locale(), { week: { dow } });
}
const uiSettings = chrome.getUiSettingsClient();
setDefaultTimezone(uiSettings.get('dateFormat:tz'));
setStartDayOfWeek(uiSettings.get('dateFormat:dow'));
uiSettings.subscribe(({ key, newValue }) => {
if (key === 'dateFormat:tz') {
setDefaultTimezone(newValue);
} else if (key === 'dateFormat:dow') {
setStartDayOfWeek(newValue);
}
});
// ----------------- END OF REMOVAL ----------
import { Main } from './components/main';
const app = uiModules.get('apps/firewallDemoPlugin', ['kibana']);
app.config($locationProvider => {
$locationProvider.html5Mode({
enabled: false,
requireBase: false,
rewriteLinks: false,
});
});
app.config(stateManagementConfigProvider =>
stateManagementConfigProvider.disable()
);
function RootController($scope, $element) {
const domNode = $element[0];
// render react to DOM
render(<Main />, domNode);
// unmount react on controller destroy
$scope.$on('$destroy', () => {
unmountComponentAtNode(domNode);
});
}
chrome.setRootController('firewallDemoPlugin', RootController);

View file

@ -0,0 +1,140 @@
/*
* 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 React from 'react';
import {
EuiFlexGroup,
EuiFlexItem,
EuiFormRow,
EuiLoadingChart,
EuiPage,
EuiPageBody,
EuiPageContent,
EuiPageContentBody,
EuiPageContentHeader,
EuiSelect,
} from '@elastic/eui';
import { embeddingSamples } from '../embedding';
const VISUALIZATION_OPTIONS = [
{ value: '', text: '' },
{ value: 'timebased', text: 'Time based' },
{ value: 'timebased_with-filters', text: 'Time based (with filters)' },
{ value: 'timebased_no-datehistogram', text: 'Time based data without date histogram' }
];
class Main extends React.Component {
chartDiv = React.createRef();
state = {
loading: false,
selectedParams: null,
selectedVis: null,
};
embedVisualization = async () => {
if (this.handler) {
// Whenever a visualization is about to be removed from DOM that you embedded,
// you need to call `destroy` on the handler to make sure the visualization is
// teared down correctly.
this.handler.destroy();
this.chartDiv.current.innerHTML = '';
}
const { selectedParams, selectedVis } = this.state;
if (selectedParams && selectedVis) {
this.setState({ loading: true });
const sample = embeddingSamples.find(el => el.id === selectedParams);
this.handler = await sample.run(this.chartDiv.current, selectedVis);
// handler.whenFirstRenderComplete() will return a promise that resolves once the first
// rendering after embedding has finished.
await this.handler.whenFirstRenderComplete();
this.setState({ loading: false });
}
}
onChangeVisualization = async (ev) => {
this.setState({
selectedVis: ev.target.value,
}, this.embedVisualization);
};
onSelectSample = async (ev) => {
this.setState({
selectedParams: ev.target.value,
}, this.embedVisualization);
};
render() {
const samples = [
{ value: '', text: '' },
...embeddingSamples.map(({ id, title }) => ({
value: id,
text: title,
}))
];
return (
<EuiPage>
<EuiPageBody>
<EuiPageContent>
<EuiPageContentHeader>
<EuiFlexGroup alignItems="center">
<EuiFlexItem grow={false}>
<EuiFormRow label="Select visualizations">
<EuiSelect
data-test-subj="visSelect"
options={VISUALIZATION_OPTIONS}
onChange={this.onChangeVisualization}
/>
</EuiFormRow>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiFormRow label="Select embedding parameters">
<EuiSelect
data-test-subj="embeddingParamsSelect"
options={samples}
onChange={this.onSelectSample}
/>
</EuiFormRow>
</EuiFlexItem>
{ this.state.loading &&
<EuiFlexItem>
<EuiLoadingChart size="xl" data-test-subj="visLoadingIndicator" />
</EuiFlexItem>
}
</EuiFlexGroup>
</EuiPageContentHeader>
<EuiPageContentBody>
{/*
The element you want to render into should have its dimension set (via a fixed height, flexbox, absolute positioning, etc.),
since the visualization will render with exactly the size of that element, i.e. the container size determines the
visualization size.
*/}
<div ref={this.chartDiv} style={{ height: '500px' }} />
</EuiPageContentBody>
</EuiPageContent>
</EuiPageBody>
</EuiPage>
);
}
}
export { Main };

View file

@ -0,0 +1,187 @@
/*
* 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.
*/
/**
* This files shows a couple of examples how to use the visualize loader API
* to embed visualizations.
*/
import { getVisualizeLoader } from 'ui/visualize';
import chrome from 'ui/chrome';
export const embeddingSamples = [
{
id: 'none',
title: 'No parameters',
async run(domNode, id) {
// You always need to retrieve the visualize loader for embedding visualizations.
const loader = await getVisualizeLoader();
// Use the embedVisualizationWithId method to embed a visualization by its id. The id is the id of the
// saved object in the .kibana index (you can find the id via Management -> Saved Objects).
//
// Pass in a DOM node that you want to embed that visualization into. Note: the loader will
// use the size of that DOM node.
//
// The call will return a handler for the visualization with methods to interact with it.
// Check the components/main.js file to see how this handler is used. Most important: you need to call
// `destroy` on the handler once you are about to remove the visualization from the DOM.
//
// Note: If the visualization you want to embed contains date histograms with an auto interval, you need
// to specify the timeRange parameter (see below).
return loader.embedVisualizationWithId(domNode, id, {});
}
}, {
id: 'timerange',
title: 'timeRange',
async run(domNode, id) {
const loader = await getVisualizeLoader();
// If you want to filter down the data to a specific time range, you can specify a
// timeRange in the parameters to the embedding call.
// You can either use an absolute time range as seen below. You can also specify
// a datemath string, like "now-7d", "now-1w/w" for the from or to key.
// You can also directly assign a moment JS or regular JavaScript Date object.
return loader.embedVisualizationWithId(domNode, id, {
timeRange: {
from: '2015-09-20 20:00:00.000',
to: '2015-09-21 20:00:00.000',
}
});
}
}, {
id: 'query',
title: 'query',
async run(domNode, id) {
const loader = await getVisualizeLoader();
// You can specify a query that should filter down the data via the query parameter.
// It must have a language key which must be one of the supported query languages of Kibana,
// which are at the moment: 'lucene' or 'kquery'.
// The query key must then hold the actual query in the specified language for filtering.
return loader.embedVisualizationWithId(domNode, id, {
query: {
language: 'lucene',
query: 'extension.raw:jpg',
}
});
}
}, {
id: 'filters',
title: 'filters',
async run(domNode, id) {
const loader = await getVisualizeLoader();
// You can specify an array of filters that should apply to the query.
// The format of a filter must match the format the filter bar is using internally.
// This has a query key, which holds the query part of an Elasticsearch query
// and a meta key allowing to set some meta values, most important for this API
// the `negate` option to negate the filter.
return loader.embedVisualizationWithId(domNode, id, {
filters: [
{
query: {
bool: {
should: [
{ match_phrase: { 'extension.raw': 'jpg' } },
{ match_phrase: { 'extension.raw': 'png' } },
]
}
},
meta: {
negate: true
}
}
]
});
}
}, {
id: 'filters_query_timerange',
title: 'filters & query & timeRange',
async run(domNode, id) {
const loader = await getVisualizeLoader();
// You an of course combine timeRange, query and filters options all together
// to filter the data in the embedded visualization.
return loader.embedVisualizationWithId(domNode, id, {
timeRange: {
from: '2015-09-20 20:00:00.000',
to: '2015-09-21 20:00:00.000',
},
query: {
language: 'lucene',
query: 'bytes:>2000'
},
filters: [
{
query: {
bool: {
should: [
{ match_phrase: { 'extension.raw': 'jpg' } },
{ match_phrase: { 'extension.raw': 'png' } },
]
}
},
meta: {
negate: true
}
}
]
});
}
}, {
id: 'savedobject_filter_query_timerange',
title: 'filters & query & time (use saved object)',
async run(domNode, id) {
const loader = await getVisualizeLoader();
// Besides embedding via the id of the visualizataion, the API offers the possibility to
// embed via the saved visualization object.
//
// WE ADVISE YOU NOT TO USE THIS INSIDE ANY PLUGIN!
//
// Since the format of the saved visualization object will change in the future and because
// this still requires you to talk to old Angular code, we do not encourage you to use this
// way of embedding in any plugin. It's likely it will be removed or changed in a future version.
const $injector = await chrome.dangerouslyGetActiveInjector();
const savedVisualizations = $injector.get('savedVisualizations');
const savedVis = await savedVisualizations.get(id);
return loader.embedVisualizationWithSavedObject(domNode, savedVis, {
timeRange: {
from: '2015-09-20 20:00:00.000',
to: '2015-09-21 20:00:00.000',
},
query: {
language: 'lucene',
query: 'bytes:>2000'
},
filters: [
{
query: {
bool: {
should: [
{ match_phrase: { 'extension.raw': 'jpg' } },
{ match_phrase: { 'extension.raw': 'png' } },
]
}
},
meta: {
negate: true
}
}
]
});
}
}
];

View file

@ -0,0 +1,188 @@
/*
* 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 'expect.js';
export default function ({ getService }) {
const testSubjects = getService('testSubjects');
const find = getService('find');
const table = getService('table');
const retry = getService('retry');
async function selectVis(id) {
await testSubjects.click('visSelect');
await find.clickByCssSelector(`option[value="${id}"]`);
}
async function selectParams(id) {
await testSubjects.click('embeddingParamsSelect');
await find.clickByCssSelector(`option[value="${id}"]`);
await retry.try(async () => {
await testSubjects.waitForDeleted('visLoadingIndicator');
});
}
async function getTableData() {
const data = await table.getDataFromTestSubj('paginated-table-body');
// Strip away empty rows (at the bottom)
return data.filter(row => !row.every(cell => !cell.trim()));
}
describe('embed by id', function describeIndexTests() {
describe('vis on timebased data without date histogram', () => {
before(async () => {
await selectVis('timebased_no-datehistogram');
});
it('should correctly embed', async () => {
await selectParams('none');
const data = await getTableData();
expect(data).to.be.eql([
['jpg', '9,109'],
['css', '2,159'],
['png', '1,373'],
['gif', '918'],
['php', '445'],
]);
});
it('should correctly embed specifying a timeRange', async () => {
await selectParams('timerange');
const data = await getTableData();
expect(data).to.be.eql([
['jpg', '3,005'],
['css', '720'],
['png', '455'],
['gif', '300'],
['php', '142'],
]);
});
it('should correctly embed specifying a query', async () => {
await selectParams('query');
const data = await getTableData();
expect(data).to.be.eql([
['jpg', '9,109'],
]);
});
it('should correctly embed specifying filters', async () => {
await selectParams('filters');
const data = await getTableData();
expect(data).to.be.eql([
['css', '2,159'],
['gif', '918'],
['php', '445'],
]);
});
it('should correctly embed specifying filters and query and timeRange', async () => {
await selectParams('filters_query_timerange');
const data = await getTableData();
expect(data).to.be.eql([
['css', '678'],
['php', '110'],
]);
});
});
describe('vis on timebased data with date histogram with interval auto', () => {
before(async () => {
await selectVis('timebased');
});
it('should correctly embed specifying a timeRange', async () => {
await selectParams('timerange');
const data = await getTableData();
expect(data).to.be.eql([
['2015-09-20 20:00', '45.159KB', '5.65KB'],
['2015-09-21 00:00', '42.428KB', '5.345KB'],
['2015-09-21 04:00', '43.717KB', '5.35KB'],
['2015-09-21 08:00', '43.228KB', '5.538KB'],
['2015-09-21 12:00', '42.83KB', '5.669KB'],
['2015-09-21 16:00', '44.908KB', '5.673KB'],
]);
});
it('should correctly embed specifying filters and query and timeRange', async () => {
await selectParams('filters_query_timerange');
const data = await getTableData();
expect(data).to.be.eql([
['2015-09-20 20:00', '45.391KB', '5.692KB'],
['2015-09-21 00:00', '46.57KB', '5.953KB'],
['2015-09-21 04:00', '47.339KB', '6.636KB'],
['2015-09-21 08:00', '40.5KB', '6.133KB'],
['2015-09-21 12:00', '41.31KB', '5.84KB'],
['2015-09-21 16:00', '48.012KB', '6.003KB'],
]);
});
});
describe('vis on timebased data with date histogram with interval auto and saved filters', () => {
before(async () => {
await selectVis('timebased_with-filters');
});
it('should correctly embed specifying a timeRange', async () => {
await selectParams('timerange');
const data = await getTableData();
expect(data).to.be.eql([
['2015-09-20 20:00', '21.221KB', '2.66KB'],
['2015-09-21 00:00', '22.054KB', '2.63KB'],
['2015-09-21 04:00', '15.592KB', '2.547KB'],
['2015-09-21 08:00', '4.656KB', '2.328KB'],
['2015-09-21 12:00', '17.887KB', '2.694KB'],
['2015-09-21 16:00', '20.533KB', '2.529KB'],
]);
});
it('should correctly embed specifying filters and query and timeRange', async () => {
await selectParams('filters_query_timerange');
const data = await getTableData();
expect(data).to.be.eql([
['2015-09-20 20:00', '24.567KB', '3.498KB'],
['2015-09-21 00:00', '25.984KB', '3.589KB'],
['2015-09-21 04:00', '2.543KB', '2.543KB'],
['2015-09-21 12:00', '5.783KB', '2.927KB'],
['2015-09-21 16:00', '21.107KB', '3.44KB'],
]);
});
});
describe('vis visa saved object on timebased data with date histogram with interval auto and saved filters', () => {
before(async () => {
await selectVis('timebased_with-filters');
});
it('should correctly embed specifying filters and query and timeRange', async () => {
await selectParams('savedobject_filter_query_timerange');
const data = await getTableData();
expect(data).to.be.eql([
['2015-09-20 20:00', '24.567KB', '3.498KB'],
['2015-09-21 00:00', '25.984KB', '3.589KB'],
['2015-09-21 04:00', '2.543KB', '2.543KB'],
['2015-09-21 12:00', '5.783KB', '2.927KB'],
['2015-09-21 16:00', '21.107KB', '3.44KB'],
]);
});
});
});
}

View file

@ -0,0 +1,38 @@
/*
* 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.
*/
export default function ({ getService, getPageObjects, loadTestFile }) {
const remote = getService('remote');
const esArchiver = getService('esArchiver');
const kibanaServer = getService('kibanaServer');
const PageObjects = getPageObjects(['common', 'header']);
describe('embedding visualizations', function () {
before(async () => {
await esArchiver.loadIfNeeded('../functional/fixtures/es_archiver/logstash_functional');
await esArchiver.load('../functional/fixtures/es_archiver/visualize_embedding');
await kibanaServer.uiSettings.replace({ 'dateFormat:tz': 'Australia/North', 'defaultIndex': 'logstash-*' });
await remote.setWindowSize(1300, 900);
await PageObjects.common.navigateToApp('settings');
await PageObjects.header.clickGlobalNavigationLink('Embedding Vis');
});
loadTestFile(require.resolve('./embed_by_id'));
});
}