From b573f0eb3deefe565d7042a2691fe588b3c06943 Mon Sep 17 00:00:00 2001 From: Alexey Antonov Date: Mon, 3 Aug 2020 18:17:19 +0300 Subject: [PATCH 01/12] [Vega] [Inspector] add functional tests for Request tab --- test/functional/apps/visualize/_vega_chart.ts | 41 ++++++++++++++++++- test/functional/services/inspector.ts | 33 +++++++++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) diff --git a/test/functional/apps/visualize/_vega_chart.ts b/test/functional/apps/visualize/_vega_chart.ts index 6c0b77411ae99..bb15eb6871865 100644 --- a/test/functional/apps/visualize/_vega_chart.ts +++ b/test/functional/apps/visualize/_vega_chart.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ - +import { unzip } from 'lodash'; import expect from '@kbn/expect'; import { FtrProviderContext } from '../../ftr_provider_context'; @@ -30,6 +30,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { 'vegaChart', ]); const filterBar = getService('filterBar'); + const inspector = getService('inspector'); const log = getService('log'); describe('vega chart in visualize app', () => { @@ -89,5 +90,43 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { }); }); }); + + describe('Inspector Panel', () => { + it('should have inspector enabled', async () => { + await inspector.expectIsEnabled(); + }); + + describe('Request Tab', () => { + beforeEach(async () => { + await inspector.open(); + }); + + afterEach(async () => { + await inspector.close(); + }); + + it('should contain Statistics, Request, Response tabs', async () => { + await inspector.openInspectorRequestsView(); + await inspector.expectRequestStatisticTabIsExists(); + await inspector.expectRequestDetailRequestTabIsExists(); + await inspector.expectRequestDetailResponseTabIsEnabled(); + }); + + it('should set the default query name if not given in the schema', async () => { + const requests = await inspector.getRequestNames(); + + expect(requests).to.be('Unnamed request #0'); + }); + + it('should log the request statistic', async () => { + await inspector.openInspectorRequestsView(); + const rawTableData = await inspector.getTableData(); + + expect(unzip(rawTableData)[0].join(', ')).to.be( + 'Hits, Hits (total), Query time, Request timestamp' + ); + }); + }); + }); }); } diff --git a/test/functional/services/inspector.ts b/test/functional/services/inspector.ts index d8ac224ddd9bc..64c7f95e354e2 100644 --- a/test/functional/services/inspector.ts +++ b/test/functional/services/inspector.ts @@ -233,6 +233,39 @@ export function InspectorProvider({ getService }: FtrProviderContext) { const singleRequest = await testSubjects.find('inspectorRequestName'); return await singleRequest.getVisibleText(); } + + public async getRequestStatisticTab() { + return testSubjects.find('inspectorRequestDetailStatistics'); + } + + public async expectRequestStatisticTabIsExists(): Promise { + await retry.try(async () => { + const requestStatisticTab = await this.getRequestStatisticTab(); + expect(await requestStatisticTab.isDisplayed()).to.be(true); + }); + } + + public async getRequestDetailRequestTab() { + return testSubjects.find('inspectorRequestDetailRequest'); + } + + public async expectRequestDetailRequestTabIsExists(): Promise { + await retry.try(async () => { + const requestStatisticTab = await this.getRequestDetailRequestTab(); + expect(await requestStatisticTab.isDisplayed()).to.be(true); + }); + } + + public async getRequestDetailResponseTab() { + return testSubjects.find('inspectorRequestDetailResponse'); + } + + public async expectRequestDetailResponseTabIsEnabled(): Promise { + await retry.try(async () => { + const requestStatisticTab = await this.getRequestDetailResponseTab(); + expect(await requestStatisticTab.isDisplayed()).to.be(true); + }); + } } return new Inspector(); From 258351b9a39fe1b49e03ecc73056e9aaa052a8d0 Mon Sep 17 00:00:00 2001 From: Alexey Antonov Date: Wed, 5 Aug 2020 16:10:41 +0300 Subject: [PATCH 02/12] add some tests for Vega Debug tab --- .../vega_inspector/components/spec_viewer.tsx | 8 ++- .../vega_inspector/vega_data_inspector.tsx | 3 + test/functional/apps/visualize/_vega_chart.ts | 63 +++++++++++++++++-- test/functional/services/common/browser.ts | 4 ++ test/functional/services/index.ts | 7 ++- test/functional/services/inspector.ts | 27 +------- .../services/visualizations/index.ts | 1 + .../visualizations/vega_debug_inspector.ts | 48 ++++++++++++++ 8 files changed, 131 insertions(+), 30 deletions(-) create mode 100644 test/functional/services/visualizations/vega_debug_inspector.ts diff --git a/src/plugins/vis_type_vega/public/vega_inspector/components/spec_viewer.tsx b/src/plugins/vis_type_vega/public/vega_inspector/components/spec_viewer.tsx index 54f7974960aa2..1c3f178eeab74 100644 --- a/src/plugins/vis_type_vega/public/vega_inspector/components/spec_viewer.tsx +++ b/src/plugins/vis_type_vega/public/vega_inspector/components/spec_viewer.tsx @@ -66,7 +66,13 @@ export const SpecViewer = ({ vegaAdapter, ...rest }: SpecViewerProps) => {
{(copy) => ( - + {copyToClipboardLabel} )} diff --git a/src/plugins/vis_type_vega/public/vega_inspector/vega_data_inspector.tsx b/src/plugins/vis_type_vega/public/vega_inspector/vega_data_inspector.tsx index 3b9427c96e62a..6dfa7a23c4fe8 100644 --- a/src/plugins/vis_type_vega/public/vega_inspector/vega_data_inspector.tsx +++ b/src/plugins/vis_type_vega/public/vega_inspector/vega_data_inspector.tsx @@ -47,11 +47,13 @@ export const VegaDataInspector = ({ adapters }: VegaDataInspectorProps) => { id: 'data-viewer--id', name: dataSetsLabel, content: , + 'data-test-subj': 'vegaDataInspectorDataViewerButton', }, { id: 'signal-viewer--id', name: signalValuesLabel, content: , + 'data-test-subj': 'vegaDataInspectorSignalViewerButton', }, { id: 'spec-viewer--id', @@ -59,6 +61,7 @@ export const VegaDataInspector = ({ adapters }: VegaDataInspectorProps) => { content: ( ), + 'data-test-subj': 'vegaDataInspectorSpecViewerButton', }, ]; diff --git a/test/functional/apps/visualize/_vega_chart.ts b/test/functional/apps/visualize/_vega_chart.ts index bb15eb6871865..9817ec42a2eeb 100644 --- a/test/functional/apps/visualize/_vega_chart.ts +++ b/test/functional/apps/visualize/_vega_chart.ts @@ -31,7 +31,10 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { ]); const filterBar = getService('filterBar'); const inspector = getService('inspector'); + const vegaDebugInspectorView = getService('vegaDebugInspector'); const log = getService('log'); + const retry = getService('retry'); + const browser = getService('browser'); describe('vega chart in visualize app', () => { before(async () => { @@ -105,11 +108,20 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await inspector.close(); }); - it('should contain Statistics, Request, Response tabs', async () => { + it('should contain "Statistics", "Request", "Response" tabs', async () => { await inspector.openInspectorRequestsView(); - await inspector.expectRequestStatisticTabIsExists(); - await inspector.expectRequestDetailRequestTabIsExists(); - await inspector.expectRequestDetailResponseTabIsEnabled(); + + for (const getFn of [ + inspector.getOpenRequestDetailRequestButton, + inspector.getOpenRequestDetailResponseButton, + inspector.getOpenRequestStatisticButton, + ]) { + await retry.try(async () => { + const requestStatisticTab = await getFn(); + + expect(await requestStatisticTab.isDisplayed()).to.be(true); + }); + } }); it('should set the default query name if not given in the schema', async () => { @@ -127,6 +139,49 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { ); }); }); + + describe('Debug Tab', () => { + beforeEach(async () => { + await inspector.open(); + }); + + afterEach(async () => { + await inspector.close(); + }); + + it('should contain "Data Sets", "Signal Values", "Spec" tabs', async () => { + await vegaDebugInspectorView.openVegaDebugInspectorView(); + + for (const getFn of [ + vegaDebugInspectorView.getOpenDataViewerButton, + vegaDebugInspectorView.getOpenSignalViewerButton, + vegaDebugInspectorView.getOpenSpecViewerButton, + ]) { + await retry.try(async () => { + const requestStatisticTab = await getFn(); + + expect(await requestStatisticTab.isDisplayed()).to.be(true); + }); + } + }); + + it('should be able to copy vega spec to clipboard', async () => { + await vegaDebugInspectorView.openVegaDebugInspectorView(); + const openSpecViewerButton = await vegaDebugInspectorView.getOpenSpecViewerButton(); + + await openSpecViewerButton.click(); + + const copyCopyToClipboardButton = await vegaDebugInspectorView.getCopyClipboardButton(); + + await copyCopyToClipboardButton.click(); + + const clipboardValue = await browser.getClipboardValue(); + + expect( + clipboardValue.includes('"$schema": "https://vega.github.io/schema/vega-lite/') + ).to.be(true); + }); + }); }); }); } diff --git a/test/functional/services/common/browser.ts b/test/functional/services/common/browser.ts index c38ac771e4162..fc3cf44f55875 100644 --- a/test/functional/services/common/browser.ts +++ b/test/functional/services/common/browser.ts @@ -481,5 +481,9 @@ export async function BrowserProvider({ getService }: FtrProviderContext) { const _id = idOrElement instanceof WebElementWrapper ? idOrElement._webElement : idOrElement; await driver.switchTo().frame(_id); } + + public getClipboardValue(): Promise { + return driver.executeAsyncScript('navigator.clipboard.readText().then(arguments[0])'); + } })(); } diff --git a/test/functional/services/index.ts b/test/functional/services/index.ts index 7891a6b00f729..6be8e4442af56 100644 --- a/test/functional/services/index.ts +++ b/test/functional/services/index.ts @@ -47,7 +47,11 @@ import { RemoteProvider } from './remote'; import { RenderableProvider } from './renderable'; import { TableProvider } from './table'; import { ToastsProvider } from './toasts'; -import { PieChartProvider, ElasticChartProvider } from './visualizations'; +import { + PieChartProvider, + ElasticChartProvider, + VegaDebugInspectorViewProvider, +} from './visualizations'; import { ListingTableProvider } from './listing_table'; import { SavedQueryManagementComponentProvider } from './saved_query_management_component'; import { KibanaSupertestProvider } from './supertest'; @@ -78,6 +82,7 @@ export const services = { browser: BrowserProvider, pieChart: PieChartProvider, inspector: InspectorProvider, + vegaDebugInspector: VegaDebugInspectorViewProvider, appsMenu: AppsMenuProvider, globalNav: GlobalNavProvider, toasts: ToastsProvider, diff --git a/test/functional/services/inspector.ts b/test/functional/services/inspector.ts index 64c7f95e354e2..1c0bf7ad46df1 100644 --- a/test/functional/services/inspector.ts +++ b/test/functional/services/inspector.ts @@ -234,38 +234,17 @@ export function InspectorProvider({ getService }: FtrProviderContext) { return await singleRequest.getVisibleText(); } - public async getRequestStatisticTab() { + public getOpenRequestStatisticButton() { return testSubjects.find('inspectorRequestDetailStatistics'); } - public async expectRequestStatisticTabIsExists(): Promise { - await retry.try(async () => { - const requestStatisticTab = await this.getRequestStatisticTab(); - expect(await requestStatisticTab.isDisplayed()).to.be(true); - }); - } - - public async getRequestDetailRequestTab() { + public getOpenRequestDetailRequestButton() { return testSubjects.find('inspectorRequestDetailRequest'); } - public async expectRequestDetailRequestTabIsExists(): Promise { - await retry.try(async () => { - const requestStatisticTab = await this.getRequestDetailRequestTab(); - expect(await requestStatisticTab.isDisplayed()).to.be(true); - }); - } - - public async getRequestDetailResponseTab() { + public getOpenRequestDetailResponseButton() { return testSubjects.find('inspectorRequestDetailResponse'); } - - public async expectRequestDetailResponseTabIsEnabled(): Promise { - await retry.try(async () => { - const requestStatisticTab = await this.getRequestDetailResponseTab(); - expect(await requestStatisticTab.isDisplayed()).to.be(true); - }); - } } return new Inspector(); diff --git a/test/functional/services/visualizations/index.ts b/test/functional/services/visualizations/index.ts index 1da1691b07c2a..10019e63d684e 100644 --- a/test/functional/services/visualizations/index.ts +++ b/test/functional/services/visualizations/index.ts @@ -19,3 +19,4 @@ export { PieChartProvider } from './pie_chart'; export { ElasticChartProvider } from './elastic_chart'; +export { VegaDebugInspectorViewProvider } from './vega_debug_inspector'; diff --git a/test/functional/services/visualizations/vega_debug_inspector.ts b/test/functional/services/visualizations/vega_debug_inspector.ts new file mode 100644 index 0000000000000..6a337d23228d7 --- /dev/null +++ b/test/functional/services/visualizations/vega_debug_inspector.ts @@ -0,0 +1,48 @@ +/* + * 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 { FtrProviderContext } from '../../ftr_provider_context'; + +export function VegaDebugInspectorViewProvider({ getService }: FtrProviderContext) { + const testSubjects = getService('testSubjects'); + const inspector = getService('inspector'); + + class VegaDebugInspectorView { + async openVegaDebugInspectorView() { + await inspector.openInspectorView('inspectorViewChooserVega debug'); + } + + public getOpenDataViewerButton() { + return testSubjects.find('vegaDataInspectorDataViewerButton'); + } + + public getOpenSignalViewerButton() { + return testSubjects.find('vegaDataInspectorSignalViewerButton'); + } + + public getOpenSpecViewerButton() { + return testSubjects.find('vegaDataInspectorSpecViewerButton'); + } + + public getCopyClipboardButton() { + return testSubjects.find('vegaDataInspectorCopyClipboardButton'); + } + } + + return new VegaDebugInspectorView(); +} From ec7e97e2dd444a5f1d24c5a98f8d647548b6786f Mon Sep 17 00:00:00 2001 From: Alexey Antonov Date: Thu, 6 Aug 2020 12:34:18 +0300 Subject: [PATCH 03/12] add clipboard permissions for webdriver --- test/functional/apps/visualize/_vega_chart.ts | 4 ++-- test/functional/services/remote/webdriver.ts | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/test/functional/apps/visualize/_vega_chart.ts b/test/functional/apps/visualize/_vega_chart.ts index 9817ec42a2eeb..5b17f07c0b628 100644 --- a/test/functional/apps/visualize/_vega_chart.ts +++ b/test/functional/apps/visualize/_vega_chart.ts @@ -119,7 +119,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await retry.try(async () => { const requestStatisticTab = await getFn(); - expect(await requestStatisticTab.isDisplayed()).to.be(true); + expect(await requestStatisticTab.isEnabled()).to.be(true); }); } }); @@ -160,7 +160,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await retry.try(async () => { const requestStatisticTab = await getFn(); - expect(await requestStatisticTab.isDisplayed()).to.be(true); + expect(await requestStatisticTab.isEnabled()).to.be(true); }); } }); diff --git a/test/functional/services/remote/webdriver.ts b/test/functional/services/remote/webdriver.ts index 09fede7fe2546..4d86d77aa9d17 100644 --- a/test/functional/services/remote/webdriver.ts +++ b/test/functional/services/remote/webdriver.ts @@ -56,6 +56,12 @@ const downloadDir = resolve(REPO_ROOT, 'target/functional-tests/downloads'); const chromiumDownloadPrefs = { 'download.default_directory': downloadDir, 'download.prompt_for_download': false, + 'profile.content_settings.exceptions.clipboard': { + '[*.],*': { + last_modified: Date.now(), + setting: 1, + }, + }, }; /** From c85de6d2bc65a3bfe49b252dc66c49e6373febd7 Mon Sep 17 00:00:00 2001 From: Alexey Antonov Date: Thu, 6 Aug 2020 17:48:06 +0300 Subject: [PATCH 04/12] add smoke tests for data grid --- test/functional/apps/visualize/_vega_chart.ts | 31 ++++++-- test/functional/services/dagta_grid.ts | 70 +++++++++++++++++++ test/functional/services/index.ts | 2 + test/functional/services/remote/webdriver.ts | 6 +- .../visualizations/vega_debug_inspector.ts | 20 ++++++ 5 files changed, 120 insertions(+), 9 deletions(-) create mode 100644 test/functional/services/dagta_grid.ts diff --git a/test/functional/apps/visualize/_vega_chart.ts b/test/functional/apps/visualize/_vega_chart.ts index 5b17f07c0b628..8846a23810b14 100644 --- a/test/functional/apps/visualize/_vega_chart.ts +++ b/test/functional/apps/visualize/_vega_chart.ts @@ -165,20 +165,39 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { } }); - it('should be able to copy vega spec to clipboard', async () => { + it('should contain data on "Signal Values" tab', async () => { + await vegaDebugInspectorView.openVegaDebugInspectorView(); + await vegaDebugInspectorView.navigateToSignalViewerTab(); + + const { rows, columns } = await vegaDebugInspectorView.getGridTableData(); + + expect(columns.join(', ')).to.be('Signal, Value'); + expect(rows.length).to.be.greaterThan(0); + expect(rows[0].length).to.be(2); + }); + + it('should contain data on "Signal Values" tab', async () => { await vegaDebugInspectorView.openVegaDebugInspectorView(); - const openSpecViewerButton = await vegaDebugInspectorView.getOpenSpecViewerButton(); + await vegaDebugInspectorView.navigateToDataViewerTab(); - await openSpecViewerButton.click(); + const { rows, columns } = await vegaDebugInspectorView.getGridTableData(); + + expect(columns.length).to.be.greaterThan(0); + expect(rows.length).to.be.greaterThan(0); + }); + + it('should be able to copy vega spec to clipboard', async () => { + await vegaDebugInspectorView.openVegaDebugInspectorView(); + await vegaDebugInspectorView.navigateToSpecViewerTab(); const copyCopyToClipboardButton = await vegaDebugInspectorView.getCopyClipboardButton(); await copyCopyToClipboardButton.click(); - const clipboardValue = await browser.getClipboardValue(); - expect( - clipboardValue.includes('"$schema": "https://vega.github.io/schema/vega-lite/') + (await browser.getClipboardValue()).includes( + '"$schema": "https://vega.github.io/schema/vega-lite/' + ) ).to.be(true); }); }); diff --git a/test/functional/services/dagta_grid.ts b/test/functional/services/dagta_grid.ts new file mode 100644 index 0000000000000..09f4e26d328de --- /dev/null +++ b/test/functional/services/dagta_grid.ts @@ -0,0 +1,70 @@ +/* + * 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 { FtrProviderContext } from '../ftr_provider_context'; + +interface TabbedGridData { + columns: string[]; + rows: string[][]; +} + +export function DataGridProvider({ getService }: FtrProviderContext) { + const retry = getService('retry'); + const testSubjects = getService('testSubjects'); + + class DataGrid { + async getColumnsData() { + const columns: TabbedGridData['columns'] = []; + const header = await retry.try(async () => await testSubjects.find('dataGridHeader')); + + for (const column of await header.findAllByClassName('euiDataGridHeaderCell__content')) { + columns.push(await column.getVisibleText()); + } + + return columns; + } + + async getRowsData() { + const rows: TabbedGridData['rows'] = []; + const rowsElements = await retry.try(async () => await testSubjects.findAll('dataGridRow')); + + for (const rowElement of rowsElements) { + const rowData = []; + const dataGridRowCells = await rowElement.findAllByTestSubject('dataGridRowCell'); + + for (const cell of dataGridRowCells) { + rowData.push(await cell.getVisibleText()); + } + + rows.push(rowData); + } + + return rows; + } + + async getDataGridTableData(): Promise { + return { + columns: await this.getColumnsData(), + rows: await this.getRowsData(), + }; + } + } + + return new DataGrid(); +} diff --git a/test/functional/services/index.ts b/test/functional/services/index.ts index 6be8e4442af56..0f024a6bda61a 100644 --- a/test/functional/services/index.ts +++ b/test/functional/services/index.ts @@ -47,6 +47,7 @@ import { RemoteProvider } from './remote'; import { RenderableProvider } from './renderable'; import { TableProvider } from './table'; import { ToastsProvider } from './toasts'; +import { DataGridProvider } from './dagta_grid'; import { PieChartProvider, ElasticChartProvider, @@ -76,6 +77,7 @@ export const services = { dashboardPanelActions: DashboardPanelActionsProvider, flyout: FlyoutProvider, comboBox: ComboBoxProvider, + dataGrid: DataGridProvider, embedding: EmbeddingProvider, renderable: RenderableProvider, table: TableProvider, diff --git a/test/functional/services/remote/webdriver.ts b/test/functional/services/remote/webdriver.ts index 4d86d77aa9d17..d51b32f3cc497 100644 --- a/test/functional/services/remote/webdriver.ts +++ b/test/functional/services/remote/webdriver.ts @@ -53,7 +53,7 @@ const SECOND = 1000; const MINUTE = 60 * SECOND; const NO_QUEUE_COMMANDS = ['getLog', 'getStatus', 'newSession', 'quit']; const downloadDir = resolve(REPO_ROOT, 'target/functional-tests/downloads'); -const chromiumDownloadPrefs = { +const chromiumUserPrefs = { 'download.default_directory': downloadDir, 'download.prompt_for_download': false, 'profile.content_settings.exceptions.clipboard': { @@ -141,7 +141,7 @@ async function attemptToCreateCommand( const prefs = new logging.Preferences(); prefs.setLevel(logging.Type.BROWSER, logging.Level.ALL); - chromeOptions.setUserPreferences(chromiumDownloadPrefs); + chromeOptions.setUserPreferences(chromiumUserPrefs); chromeOptions.setLoggingPrefs(prefs); chromeOptions.set('unexpectedAlertBehaviour', 'accept'); chromeOptions.setAcceptInsecureCerts(config.acceptInsecureCerts); @@ -191,7 +191,7 @@ async function attemptToCreateCommand( edgeOptions.setBinaryPath(edgePaths.browserPath); const options = edgeOptions.get('ms:edgeOptions'); // overriding options to include preferences - Object.assign(options, { prefs: chromiumDownloadPrefs }); + Object.assign(options, { prefs: chromiumUserPrefs }); edgeOptions.set('ms:edgeOptions', options); const session = await new Builder() .forBrowser('MicrosoftEdge') diff --git a/test/functional/services/visualizations/vega_debug_inspector.ts b/test/functional/services/visualizations/vega_debug_inspector.ts index 6a337d23228d7..3847ebbbf1279 100644 --- a/test/functional/services/visualizations/vega_debug_inspector.ts +++ b/test/functional/services/visualizations/vega_debug_inspector.ts @@ -21,6 +21,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export function VegaDebugInspectorViewProvider({ getService }: FtrProviderContext) { const testSubjects = getService('testSubjects'); const inspector = getService('inspector'); + const dataGrid = getService('dataGrid'); class VegaDebugInspectorView { async openVegaDebugInspectorView() { @@ -42,6 +43,25 @@ export function VegaDebugInspectorViewProvider({ getService }: FtrProviderContex public getCopyClipboardButton() { return testSubjects.find('vegaDataInspectorCopyClipboardButton'); } + + public getGridTableData() { + return dataGrid.getDataGridTableData(); + } + + public async navigateToDataViewerTab() { + const dataViewerButton = await this.getOpenDataViewerButton(); + await dataViewerButton.click(); + } + + public async navigateToSignalViewerTab() { + const signalViewerButton = await this.getOpenSignalViewerButton(); + await signalViewerButton.click(); + } + + public async navigateToSpecViewerTab() { + const specViewerButton = await this.getOpenSpecViewerButton(); + await specViewerButton.click(); + } } return new VegaDebugInspectorView(); From 92c90cfeb885fce4f4e498ebcd05031295287cf5 Mon Sep 17 00:00:00 2001 From: Alexey Antonov Date: Fri, 7 Aug 2020 13:12:31 +0300 Subject: [PATCH 05/12] fix CI --- test/functional/apps/visualize/_vega_chart.ts | 5 +++++ test/functional/services/common/browser.ts | 8 ++++++++ 2 files changed, 13 insertions(+) diff --git a/test/functional/apps/visualize/_vega_chart.ts b/test/functional/apps/visualize/_vega_chart.ts index 8846a23810b14..ddf5a4bf5ecf3 100644 --- a/test/functional/apps/visualize/_vega_chart.ts +++ b/test/functional/apps/visualize/_vega_chart.ts @@ -187,6 +187,11 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { }); it('should be able to copy vega spec to clipboard', async () => { + // The "clipboard-read" permission of the Permissions API must be granted before you can execute that test + if (!(await browser.checkBrowserPermission('clipboard-read'))) { + return; + } + await vegaDebugInspectorView.openVegaDebugInspectorView(); await vegaDebugInspectorView.navigateToSpecViewerTab(); diff --git a/test/functional/services/common/browser.ts b/test/functional/services/common/browser.ts index fc3cf44f55875..d3ede3f804056 100644 --- a/test/functional/services/common/browser.ts +++ b/test/functional/services/common/browser.ts @@ -482,6 +482,14 @@ export async function BrowserProvider({ getService }: FtrProviderContext) { await driver.switchTo().frame(_id); } + public async checkBrowserPermission(permission: string): Promise { + const result: any = await driver.executeAsyncScript( + `navigator.permissions.query({name:'${permission}'}).then(arguments[0])` + ); + + return Boolean(result?.state === 'granted'); + } + public getClipboardValue(): Promise { return driver.executeAsyncScript('navigator.clipboard.readText().then(arguments[0])'); } From 4e1fe19f17b131b0d754183e48723b13799272c7 Mon Sep 17 00:00:00 2001 From: Alexey Antonov Date: Fri, 7 Aug 2020 16:11:47 +0300 Subject: [PATCH 06/12] add some tests for vega expression funcitons --- test/functional/apps/visualize/_vega_chart.ts | 84 +++++++++++++++++-- .../page_objects/vega_chart_page.ts | 27 ++++-- 2 files changed, 99 insertions(+), 12 deletions(-) diff --git a/test/functional/apps/visualize/_vega_chart.ts b/test/functional/apps/visualize/_vega_chart.ts index ddf5a4bf5ecf3..d86a03f9041eb 100644 --- a/test/functional/apps/visualize/_vega_chart.ts +++ b/test/functional/apps/visualize/_vega_chart.ts @@ -20,6 +20,20 @@ import { unzip } from 'lodash'; import expect from '@kbn/expect'; import { FtrProviderContext } from '../../ftr_provider_context'; +const getTestSpec = (expression: string) => `{ +config: { "kibana": {"renderer": "svg"} } +$schema: https://vega.github.io/schema/vega/v5.json +marks: [{ + type: text + encode: { update: { text: { value: "Test" } } } +}] +signals: [ { + on: [{ + events: click + update: ${expression} + }] +}]}`; + // eslint-disable-next-line import/no-default-export export default function ({ getPageObjects, getService }: FtrProviderContext) { const PageObjects = getPageObjects([ @@ -94,6 +108,64 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { }); }); + describe('Vega extension functions', () => { + beforeEach(async () => { + await PageObjects.vegaChart.cleanSpec(); + await filterBar.removeAllFilters(); + }); + + const fillSpecAndGo = async (newSpec: string) => { + await PageObjects.vegaChart.cleanSpec(); + await PageObjects.vegaChart.typeInSpec(newSpec); + await PageObjects.visEditor.clickGo(); + + const viewContainer = await PageObjects.vegaChart.getViewContainer(); + const textElement = await viewContainer.findByTagName('text'); + + await textElement.click(); + }; + + it('should update global time range by calling "kibanaSetTimeFilter" expression', async () => { + await fillSpecAndGo(getTestSpec('kibanaSetTimeFilter("2019", "2020")')); + + const currentTimeRange = await PageObjects.timePicker.getTimeConfig(); + + expect(currentTimeRange.start).to.be('Jan 1, 2019 @ 00:00:00.000'); + expect(currentTimeRange.end).to.be('Jan 1, 2020 @ 00:00:00.000'); + }); + + it('should set filter by calling "kibanaAddFilter" expression', async () => { + await fillSpecAndGo( + getTestSpec('kibanaAddFilter({ query_string: { query: "response:200" }})') + ); + + expect(await filterBar.getFilterCount()).to.be(1); + }); + + it('should remove filter by calling "kibanaRemoveFilter" expression', async () => { + await filterBar.addFilter('response', 'is', '200'); + + expect(await filterBar.getFilterCount()).to.be(1); + + await fillSpecAndGo( + getTestSpec('kibanaRemoveFilter({ match_phrase: { response: "200" }})') + ); + + expect(await filterBar.getFilterCount()).to.be(0); + }); + + it('should remove all filters by calling "kibanaRemoveAllFilters" expression', async () => { + await filterBar.addFilter('response', 'is', '200'); + await filterBar.addFilter('response', 'is', '500'); + + expect(await filterBar.getFilterCount()).to.be(2); + + await fillSpecAndGo(getTestSpec('kibanaRemoveAllFilters()')); + + expect(await filterBar.getFilterCount()).to.be(0); + }); + }); + describe('Inspector Panel', () => { it('should have inspector enabled', async () => { await inspector.expectIsEnabled(); @@ -187,16 +259,18 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { }); it('should be able to copy vega spec to clipboard', async () => { - // The "clipboard-read" permission of the Permissions API must be granted before you can execute that test - if (!(await browser.checkBrowserPermission('clipboard-read'))) { - return; - } - await vegaDebugInspectorView.openVegaDebugInspectorView(); await vegaDebugInspectorView.navigateToSpecViewerTab(); const copyCopyToClipboardButton = await vegaDebugInspectorView.getCopyClipboardButton(); + expect(await copyCopyToClipboardButton.isEnabled()).to.be(true); + + // The "clipboard-read" permission of the Permissions API must be granted + if (!(await browser.checkBrowserPermission('clipboard-read'))) { + return; + } + await copyCopyToClipboardButton.click(); expect( diff --git a/test/functional/page_objects/vega_chart_page.ts b/test/functional/page_objects/vega_chart_page.ts index b9906911b00f1..5c3f03c42ec98 100644 --- a/test/functional/page_objects/vega_chart_page.ts +++ b/test/functional/page_objects/vega_chart_page.ts @@ -30,9 +30,21 @@ export function VegaChartPageProvider({ const { common } = getPageObjects(['common']); class VegaChartPage { + public getEditor() { + return testSubjects.find('vega-editor'); + } + + public getViewContainer() { + return find.byCssSelector('div.vgaVis__view'); + } + + public getControlContainer() { + return find.byCssSelector('div.vgaVis__controls'); + } + public async getSpec() { // Adapted from console_page.js:getVisibleTextFromAceEditor(). Is there a common utilities file? - const editor = await testSubjects.find('vega-editor'); + const editor = await this.getEditor(); const lines = await editor.findAllByClassName('ace_line_group'); const linesText = await Promise.all( lines.map(async (line) => { @@ -43,7 +55,7 @@ export function VegaChartPageProvider({ } public async typeInSpec(text: string) { - const editor = await testSubjects.find('vega-editor'); + const editor = await this.getEditor(); const textarea = await editor.findByClassName('ace_content'); await textarea.click(); let repeats = 20; @@ -55,12 +67,13 @@ export function VegaChartPageProvider({ await browser.pressKeys(text); } - public async getViewContainer() { - return await find.byCssSelector('div.vgaVis__view'); - } + public async cleanSpec() { + const editor = await this.getEditor(); + const aceGutter = await editor.findByClassName('ace_gutter'); - public async getControlContainer() { - return await find.byCssSelector('div.vgaVis__controls'); + // select all spec + await aceGutter.doubleClick(); + await browser.pressKeys(Key.BACK_SPACE); } public async getYAxisLabels() { From 0d84a64c7b878268ec8388a9a92f1e35041f3670 Mon Sep 17 00:00:00 2001 From: Alexey Antonov Date: Fri, 7 Aug 2020 19:01:25 +0300 Subject: [PATCH 07/12] change order --- test/functional/apps/visualize/_vega_chart.ts | 116 +++++++++--------- 1 file changed, 58 insertions(+), 58 deletions(-) diff --git a/test/functional/apps/visualize/_vega_chart.ts b/test/functional/apps/visualize/_vega_chart.ts index 675e5200f62d7..1a9f8f1a02e20 100644 --- a/test/functional/apps/visualize/_vega_chart.ts +++ b/test/functional/apps/visualize/_vega_chart.ts @@ -108,64 +108,6 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { }); }); - describe('Vega extension functions', () => { - beforeEach(async () => { - await PageObjects.vegaChart.cleanSpec(); - await filterBar.removeAllFilters(); - }); - - const fillSpecAndGo = async (newSpec: string) => { - await PageObjects.vegaChart.cleanSpec(); - await PageObjects.vegaChart.typeInSpec(newSpec); - await PageObjects.visEditor.clickGo(); - - const viewContainer = await PageObjects.vegaChart.getViewContainer(); - const textElement = await viewContainer.findByTagName('text'); - - await textElement.click(); - }; - - it('should update global time range by calling "kibanaSetTimeFilter" expression', async () => { - await fillSpecAndGo(getTestSpec('kibanaSetTimeFilter("2019", "2020")')); - - const currentTimeRange = await PageObjects.timePicker.getTimeConfig(); - - expect(currentTimeRange.start).to.be('Jan 1, 2019 @ 00:00:00.000'); - expect(currentTimeRange.end).to.be('Jan 1, 2020 @ 00:00:00.000'); - }); - - it('should set filter by calling "kibanaAddFilter" expression', async () => { - await fillSpecAndGo( - getTestSpec('kibanaAddFilter({ query_string: { query: "response:200" }})') - ); - - expect(await filterBar.getFilterCount()).to.be(1); - }); - - it('should remove filter by calling "kibanaRemoveFilter" expression', async () => { - await filterBar.addFilter('response', 'is', '200'); - - expect(await filterBar.getFilterCount()).to.be(1); - - await fillSpecAndGo( - getTestSpec('kibanaRemoveFilter({ match_phrase: { response: "200" }})') - ); - - expect(await filterBar.getFilterCount()).to.be(0); - }); - - it('should remove all filters by calling "kibanaRemoveAllFilters" expression', async () => { - await filterBar.addFilter('response', 'is', '200'); - await filterBar.addFilter('response', 'is', '500'); - - expect(await filterBar.getFilterCount()).to.be(2); - - await fillSpecAndGo(getTestSpec('kibanaRemoveAllFilters()')); - - expect(await filterBar.getFilterCount()).to.be(0); - }); - }); - describe('Inspector Panel', () => { it('should have inspector enabled', async () => { await inspector.expectIsEnabled(); @@ -281,5 +223,63 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { }); }); }); + + describe('Vega extension functions', () => { + beforeEach(async () => { + await PageObjects.vegaChart.cleanSpec(); + await filterBar.removeAllFilters(); + }); + + const fillSpecAndGo = async (newSpec: string) => { + await PageObjects.vegaChart.cleanSpec(); + await PageObjects.vegaChart.typeInSpec(newSpec); + await PageObjects.visEditor.clickGo(); + + const viewContainer = await PageObjects.vegaChart.getViewContainer(); + const textElement = await viewContainer.findByTagName('text'); + + await textElement.click(); + }; + + it('should update global time range by calling "kibanaSetTimeFilter" expression', async () => { + await fillSpecAndGo(getTestSpec('kibanaSetTimeFilter("2019", "2020")')); + + const currentTimeRange = await PageObjects.timePicker.getTimeConfig(); + + expect(currentTimeRange.start).to.be('Jan 1, 2019 @ 00:00:00.000'); + expect(currentTimeRange.end).to.be('Jan 1, 2020 @ 00:00:00.000'); + }); + + it('should set filter by calling "kibanaAddFilter" expression', async () => { + await fillSpecAndGo( + getTestSpec('kibanaAddFilter({ query_string: { query: "response:200" }})') + ); + + expect(await filterBar.getFilterCount()).to.be(1); + }); + + it('should remove filter by calling "kibanaRemoveFilter" expression', async () => { + await filterBar.addFilter('response', 'is', '200'); + + expect(await filterBar.getFilterCount()).to.be(1); + + await fillSpecAndGo( + getTestSpec('kibanaRemoveFilter({ match_phrase: { response: "200" }})') + ); + + expect(await filterBar.getFilterCount()).to.be(0); + }); + + it('should remove all filters by calling "kibanaRemoveAllFilters" expression', async () => { + await filterBar.addFilter('response', 'is', '200'); + await filterBar.addFilter('response', 'is', '500'); + + expect(await filterBar.getFilterCount()).to.be(2); + + await fillSpecAndGo(getTestSpec('kibanaRemoveAllFilters()')); + + expect(await filterBar.getFilterCount()).to.be(0); + }); + }); }); } From 60fa7afe25dc94ac28332460d40e78170d8b61e2 Mon Sep 17 00:00:00 2001 From: Alexey Antonov Date: Mon, 10 Aug 2020 12:29:15 +0300 Subject: [PATCH 08/12] Update _vega_chart.ts --- test/functional/apps/visualize/_vega_chart.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/test/functional/apps/visualize/_vega_chart.ts b/test/functional/apps/visualize/_vega_chart.ts index 1a9f8f1a02e20..6fa6997145308 100644 --- a/test/functional/apps/visualize/_vega_chart.ts +++ b/test/functional/apps/visualize/_vega_chart.ts @@ -34,7 +34,6 @@ signals: [ { }] }]}`; - export default function ({ getPageObjects, getService }: FtrProviderContext) { const PageObjects = getPageObjects([ 'timePicker', From 96b2efee573d09cd777b78c476ce73b53e3ae2ef Mon Sep 17 00:00:00 2001 From: Alexey Antonov Date: Mon, 10 Aug 2020 14:23:08 +0300 Subject: [PATCH 09/12] Rename dagta_grid.ts to data_grid.ts --- test/functional/services/{dagta_grid.ts => data_grid.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename test/functional/services/{dagta_grid.ts => data_grid.ts} (100%) diff --git a/test/functional/services/dagta_grid.ts b/test/functional/services/data_grid.ts similarity index 100% rename from test/functional/services/dagta_grid.ts rename to test/functional/services/data_grid.ts From cf8ec00f612cc849bf6891b6734e4616ef546454 Mon Sep 17 00:00:00 2001 From: Alexey Antonov Date: Mon, 10 Aug 2020 14:25:55 +0300 Subject: [PATCH 10/12] Update index.ts --- test/functional/services/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/functional/services/index.ts b/test/functional/services/index.ts index 0f024a6bda61a..4c97d672bae2e 100644 --- a/test/functional/services/index.ts +++ b/test/functional/services/index.ts @@ -47,7 +47,7 @@ import { RemoteProvider } from './remote'; import { RenderableProvider } from './renderable'; import { TableProvider } from './table'; import { ToastsProvider } from './toasts'; -import { DataGridProvider } from './dagta_grid'; +import { DataGridProvider } from './data_grid'; import { PieChartProvider, ElasticChartProvider, From f11ce9493d2972f5572fc97f31ed317baf9c73bf Mon Sep 17 00:00:00 2001 From: Alexey Antonov Date: Mon, 10 Aug 2020 16:36:58 +0300 Subject: [PATCH 11/12] Update data_grid.ts --- test/functional/services/data_grid.ts | 51 ++++++++++----------------- 1 file changed, 18 insertions(+), 33 deletions(-) diff --git a/test/functional/services/data_grid.ts b/test/functional/services/data_grid.ts index 09f4e26d328de..40157caab5756 100644 --- a/test/functional/services/data_grid.ts +++ b/test/functional/services/data_grid.ts @@ -25,43 +25,28 @@ interface TabbedGridData { } export function DataGridProvider({ getService }: FtrProviderContext) { - const retry = getService('retry'); - const testSubjects = getService('testSubjects'); + const find = getService('find'); class DataGrid { - async getColumnsData() { - const columns: TabbedGridData['columns'] = []; - const header = await retry.try(async () => await testSubjects.find('dataGridHeader')); - - for (const column of await header.findAllByClassName('euiDataGridHeaderCell__content')) { - columns.push(await column.getVisibleText()); - } - - return columns; - } - - async getRowsData() { - const rows: TabbedGridData['rows'] = []; - const rowsElements = await retry.try(async () => await testSubjects.findAll('dataGridRow')); - - for (const rowElement of rowsElements) { - const rowData = []; - const dataGridRowCells = await rowElement.findAllByTestSubject('dataGridRowCell'); - - for (const cell of dataGridRowCells) { - rowData.push(await cell.getVisibleText()); - } - - rows.push(rowData); - } - - return rows; - } - async getDataGridTableData(): Promise { + const table = await find.byCssSelector('.euiDataGrid'); + const $ = await table.parseDomContent(); + + const columns = $('.euiDataGridHeaderCell__content') + .toArray() + .map((cell) => $(cell).text()); + const rows = $.findTestSubjects('dataGridRow') + .toArray() + .map((row) => + $(row) + .find('.euiDataGridRowCell__truncate') + .toArray() + .map((cell) => $(cell).text()) + ); + return { - columns: await this.getColumnsData(), - rows: await this.getRowsData(), + columns, + rows, }; } } From 8a9c069b4693ca87cb462edf078296890bcfcb4b Mon Sep 17 00:00:00 2001 From: Alexey Antonov Date: Tue, 11 Aug 2020 20:46:37 +0300 Subject: [PATCH 12/12] stabilize tests --- .../public/components/vega_actions_menu.tsx | 2 +- test/functional/apps/visualize/_vega_chart.ts | 7 ++- .../page_objects/vega_chart_page.ts | 44 ++++++++++++++++--- 3 files changed, 41 insertions(+), 12 deletions(-) diff --git a/src/plugins/vis_type_vega/public/components/vega_actions_menu.tsx b/src/plugins/vis_type_vega/public/components/vega_actions_menu.tsx index f10954df432c2..33fa1ceefd3d5 100644 --- a/src/plugins/vis_type_vega/public/components/vega_actions_menu.tsx +++ b/src/plugins/vis_type_vega/public/components/vega_actions_menu.tsx @@ -70,7 +70,7 @@ function VegaActionsMenu({ formatHJson, formatJson }: VegaActionsMenuProps) { return ( `{ +const getTestSpec = (expression: string) => ` +{ config: { "kibana": {"renderer": "svg"} } $schema: https://vega.github.io/schema/vega/v5.json marks: [{ @@ -225,13 +226,11 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { describe('Vega extension functions', () => { beforeEach(async () => { - await PageObjects.vegaChart.cleanSpec(); await filterBar.removeAllFilters(); }); const fillSpecAndGo = async (newSpec: string) => { - await PageObjects.vegaChart.cleanSpec(); - await PageObjects.vegaChart.typeInSpec(newSpec); + await PageObjects.vegaChart.fillSpec(newSpec); await PageObjects.visEditor.clickGo(); const viewContainer = await PageObjects.vegaChart.getViewContainer(); diff --git a/test/functional/page_objects/vega_chart_page.ts b/test/functional/page_objects/vega_chart_page.ts index 5c3f03c42ec98..1173c35af3384 100644 --- a/test/functional/page_objects/vega_chart_page.ts +++ b/test/functional/page_objects/vega_chart_page.ts @@ -18,8 +18,14 @@ */ import { Key } from 'selenium-webdriver'; +import expect from '@kbn/expect'; import { FtrProviderContext } from '../ftr_provider_context'; +const compareSpecs = (first: string, second: string) => { + const normalizeSpec = (spec: string) => spec.replace(/[\n ]/g, ''); + return normalizeSpec(first) === normalizeSpec(second); +}; + export function VegaChartPageProvider({ getService, getPageObjects, @@ -28,6 +34,7 @@ export function VegaChartPageProvider({ const testSubjects = getService('testSubjects'); const browser = getService('browser'); const { common } = getPageObjects(['common']); + const retry = getService('retry'); class VegaChartPage { public getEditor() { @@ -42,22 +49,42 @@ export function VegaChartPageProvider({ return find.byCssSelector('div.vgaVis__controls'); } - public async getSpec() { + public async getRawSpec() { // Adapted from console_page.js:getVisibleTextFromAceEditor(). Is there a common utilities file? const editor = await this.getEditor(); const lines = await editor.findAllByClassName('ace_line_group'); - const linesText = await Promise.all( + + return await Promise.all( lines.map(async (line) => { return await line.getVisibleText(); }) ); - return linesText.join('\n'); } - public async typeInSpec(text: string) { + public async getSpec() { + return (await this.getRawSpec()).join('\n'); + } + + public async focusEditor() { const editor = await this.getEditor(); const textarea = await editor.findByClassName('ace_content'); + await textarea.click(); + } + + public async fillSpec(newSpec: string) { + await retry.try(async () => { + await this.cleanSpec(); + await this.focusEditor(); + await browser.pressKeys(newSpec); + + expect(compareSpecs(await this.getSpec(), newSpec)).to.be(true); + }); + } + + public async typeInSpec(text: string) { + await this.focusEditor(); + let repeats = 20; while (--repeats > 0) { await browser.pressKeys(Key.ARROW_UP); @@ -71,9 +98,12 @@ export function VegaChartPageProvider({ const editor = await this.getEditor(); const aceGutter = await editor.findByClassName('ace_gutter'); - // select all spec - await aceGutter.doubleClick(); - await browser.pressKeys(Key.BACK_SPACE); + await retry.try(async () => { + await aceGutter.doubleClick(); + await browser.pressKeys(Key.BACK_SPACE); + + expect(await this.getSpec()).to.be(''); + }); } public async getYAxisLabels() {