Skip to content

Commit

Permalink
[Vega] add functional tests for Vega visualization (#74097) (#74843)
Browse files Browse the repository at this point in the history
* [Vega] [Inspector] add functional tests for Request tab

* add some tests for Vega Debug tab

* add clipboard permissions for webdriver

* add smoke tests for data grid

* fix CI

* add some tests for vega expression funcitons

* change order

* Update _vega_chart.ts

* Rename dagta_grid.ts to data_grid.ts

* Update index.ts

* Update data_grid.ts

* stabilize tests

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
  • Loading branch information
alexwizp and elasticmachine authored Aug 12, 2020
1 parent a667492 commit 32c9e2c
Show file tree
Hide file tree
Showing 12 changed files with 422 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ function VegaActionsMenu({ formatHJson, formatJson }: VegaActionsMenuProps) {

return (
<EuiPopover
id="helpMenu"
id="actionsMenu"
button={button}
isOpen={isPopoverOpen}
closePopover={closePopover}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,13 @@ export const SpecViewer = ({ vegaAdapter, ...rest }: SpecViewerProps) => {
<div className="eui-textRight">
<EuiCopy textToCopy={spec}>
{(copy) => (
<EuiButtonEmpty size="xs" flush="right" iconType="copyClipboard" onClick={copy}>
<EuiButtonEmpty
size="xs"
flush="right"
iconType="copyClipboard"
onClick={copy}
data-test-subj="vegaDataInspectorCopyClipboardButton"
>
{copyToClipboardLabel}
</EuiButtonEmpty>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,18 +47,21 @@ export const VegaDataInspector = ({ adapters }: VegaDataInspectorProps) => {
id: 'data-viewer--id',
name: dataSetsLabel,
content: <DataViewer vegaAdapter={adapters.vega} />,
'data-test-subj': 'vegaDataInspectorDataViewerButton',
},
{
id: 'signal-viewer--id',
name: signalValuesLabel,
content: <SignalViewer vegaAdapter={adapters.vega} />,
'data-test-subj': 'vegaDataInspectorSignalViewerButton',
},
{
id: 'spec-viewer--id',
name: specLabel,
content: (
<SpecViewer className="vgaVegaDataInspector__specViewer" vegaAdapter={adapters.vega} />
),
'data-test-subj': 'vegaDataInspectorSpecViewerButton',
},
];

Expand Down
193 changes: 192 additions & 1 deletion test/functional/apps/visualize/_vega_chart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,25 @@
* specific language governing permissions and limitations
* under the License.
*/

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}
}]
}]}`;

export default function ({ getPageObjects, getService }: FtrProviderContext) {
const PageObjects = getPageObjects([
'timePicker',
Expand All @@ -29,7 +44,11 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
'vegaChart',
]);
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 () => {
Expand Down Expand Up @@ -88,5 +107,177 @@ 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();

for (const getFn of [
inspector.getOpenRequestDetailRequestButton,
inspector.getOpenRequestDetailResponseButton,
inspector.getOpenRequestStatisticButton,
]) {
await retry.try(async () => {
const requestStatisticTab = await getFn();

expect(await requestStatisticTab.isEnabled()).to.be(true);
});
}
});

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'
);
});
});

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.isEnabled()).to.be(true);
});
}
});

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();
await vegaDebugInspectorView.navigateToDataViewerTab();

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();

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(
(await browser.getClipboardValue()).includes(
'"$schema": "https://vega.github.io/schema/vega-lite/'
)
).to.be(true);
});
});
});

describe('Vega extension functions', () => {
beforeEach(async () => {
await filterBar.removeAllFilters();
});

const fillSpecAndGo = async (newSpec: string) => {
await PageObjects.vegaChart.fillSpec(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);
});
});
});
}
65 changes: 54 additions & 11 deletions test/functional/page_objects/vega_chart_page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -28,24 +34,57 @@ export function VegaChartPageProvider({
const testSubjects = getService('testSubjects');
const browser = getService('browser');
const { common } = getPageObjects(['common']);
const retry = getService('retry');

class VegaChartPage {
public async getSpec() {
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 getRawSpec() {
// 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(

return await Promise.all(
lines.map(async (line) => {
return await line.getVisibleText();
})
);
return linesText.join('\n');
}

public async typeInSpec(text: string) {
const editor = await testSubjects.find('vega-editor');
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);
Expand All @@ -55,12 +94,16 @@ 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');

await retry.try(async () => {
await aceGutter.doubleClick();
await browser.pressKeys(Key.BACK_SPACE);

public async getControlContainer() {
return await find.byCssSelector('div.vgaVis__controls');
expect(await this.getSpec()).to.be('');
});
}

public async getYAxisLabels() {
Expand Down
12 changes: 12 additions & 0 deletions test/functional/services/common/browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -487,5 +487,17 @@ export async function BrowserProvider({ getService }: FtrProviderContext) {
const _id = idOrElement instanceof WebElementWrapper ? idOrElement._webElement : idOrElement;
await driver.switchTo().frame(_id);
}

public async checkBrowserPermission(permission: string): Promise<boolean> {
const result: any = await driver.executeAsyncScript(
`navigator.permissions.query({name:'${permission}'}).then(arguments[0])`
);

return Boolean(result?.state === 'granted');
}

public getClipboardValue(): Promise<string> {
return driver.executeAsyncScript('navigator.clipboard.readText().then(arguments[0])');
}
})();
}
Loading

0 comments on commit 32c9e2c

Please sign in to comment.