[Lens] adding some functional tests (#77863)

This commit is contained in:
Marta Bondyra 2020-09-18 18:41:22 +02:00 committed by GitHub
parent 4980af7565
commit 8ce495b6bc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 212 additions and 26 deletions

View file

@ -118,6 +118,7 @@ export const QueryInput = ({
return (
<QueryStringInput
dataTestSubj="indexPattern-filters-queryStringInput"
size="s"
isInvalid={isInvalid}
bubbleSubmitEvent={false}

View file

@ -20,7 +20,12 @@ import {
} from '@elastic/eui';
export const NewBucketButton = ({ label, onClick }: { label: string; onClick: () => void }) => (
<EuiButtonEmpty size="xs" iconType="plusInCircle" onClick={onClick}>
<EuiButtonEmpty
data-test-subj="lns-newBucket-add"
size="xs"
iconType="plusInCircle"
onClick={onClick}
>
{label}
</EuiButtonEmpty>
);

View file

@ -126,6 +126,7 @@ export function PieToolbar(props: VisualizationToolbarProps<PieVisualizationStat
})}
type="values"
groupPosition="left"
buttonDataTestSubj="lnsLabelsButton"
>
<EuiFormRow
label={i18n.translate('xpack.lens.pieChart.labelPositionLabel', {

View file

@ -93,6 +93,7 @@ export const LegendSettingsPopover: React.FunctionComponent<LegendSettingsPopove
})}
type="legend"
groupPosition="right"
buttonDataTestSubj="lnsLegendButton"
>
<EuiFormRow
display="columnCompressed"

View file

@ -33,6 +33,7 @@ export type ToolbarButtonProps = PropsOf<typeof EuiButton> & {
* Adjusts the borders for groupings
*/
groupPosition?: 'none' | 'left' | 'center' | 'right';
dataTestSubj?: string;
};
export const ToolbarButton: React.FunctionComponent<ToolbarButtonProps> = ({
@ -42,6 +43,7 @@ export const ToolbarButton: React.FunctionComponent<ToolbarButtonProps> = ({
size = 'm',
hasArrow = true,
groupPosition = 'none',
dataTestSubj = '',
...rest
}) => {
const classes = classNames(
@ -52,6 +54,7 @@ export const ToolbarButton: React.FunctionComponent<ToolbarButtonProps> = ({
);
return (
<EuiButton
data-test-subj={dataTestSubj}
className={classes}
iconSide="right"
iconType={hasArrow ? 'arrowDown' : ''}

View file

@ -31,6 +31,7 @@ export interface ToolbarPopoverProps {
* Button group position
*/
groupPosition?: ToolbarButtonProps['groupPosition'];
buttonDataTestSubj?: string;
}
export const ToolbarPopover: React.FunctionComponent<ToolbarPopoverProps> = ({
@ -39,6 +40,7 @@ export const ToolbarPopover: React.FunctionComponent<ToolbarPopoverProps> = ({
type,
isDisabled = false,
groupPosition,
buttonDataTestSubj,
}) => {
const [open, setOpen] = useState(false);
@ -60,6 +62,7 @@ export const ToolbarPopover: React.FunctionComponent<ToolbarPopoverProps> = ({
hasArrow={false}
isDisabled={isDisabled}
groupPosition={groupPosition}
dataTestSubj={buttonDataTestSubj}
>
<EuiIcon type={iconType} />
</ToolbarButton>

View file

@ -73,7 +73,12 @@ export interface AxisSettingsPopoverProps {
const popoverConfig = (
axis: AxesSettingsConfigKeys,
isHorizontal: boolean
): { icon: IconType; groupPosition: ToolbarButtonProps['groupPosition']; popoverTitle: string } => {
): {
icon: IconType;
groupPosition: ToolbarButtonProps['groupPosition'];
popoverTitle: string;
buttonDataTestSubj: string;
} => {
switch (axis) {
case 'yLeft':
return {
@ -86,6 +91,7 @@ const popoverConfig = (
: i18n.translate('xpack.lens.xyChart.leftAxisLabel', {
defaultMessage: 'Left axis',
}),
buttonDataTestSubj: 'lnsLeftAxisButton',
};
case 'yRight':
return {
@ -98,6 +104,7 @@ const popoverConfig = (
: i18n.translate('xpack.lens.xyChart.rightAxisLabel', {
defaultMessage: 'Right axis',
}),
buttonDataTestSubj: 'lnsRightAxisButton',
};
case 'x':
default:
@ -111,6 +118,8 @@ const popoverConfig = (
: i18n.translate('xpack.lens.xyChart.bottomAxisLabel', {
defaultMessage: 'Bottom axis',
}),
buttonDataTestSubj: 'lnsBottomAxisButton',
};
}
};
@ -143,6 +152,7 @@ export const AxisSettingsPopover: React.FunctionComponent<AxisSettingsPopoverPro
type={config.icon}
groupPosition={config.groupPosition}
isDisabled={isDisabled}
buttonDataTestSubj={config.buttonDataTestSubj}
>
<EuiFlexGroup gutterSize="s" justifyContent="spaceBetween">
<EuiFlexItem grow={false}>

View file

@ -208,6 +208,7 @@ export function XyToolbar(props: VisualizationToolbarProps<State>) {
isDisabled={!hasNonBarSeries}
type="values"
groupPosition="left"
buttonDataTestSubj="lnsMissingValuesButton"
>
<EuiFormRow
display="columnCompressed"
@ -216,6 +217,7 @@ export function XyToolbar(props: VisualizationToolbarProps<State>) {
})}
>
<EuiSuperSelect
data-test-subj="lnsMissingValuesSelect"
compressed
options={fittingFunctionDefinitions.map(({ id, title, description }) => {
return {
@ -488,6 +490,7 @@ const ColorPicker = ({
const colorPicker = (
<EuiColorPicker
data-test-subj="indexPattern-dimension-colorPicker"
compressed
isClearable
onChange={handleColor}

View file

@ -40,18 +40,21 @@ export default function ({ getPageObjects, getService }) {
operation: 'date_histogram',
field: '@timestamp',
});
await PageObjects.lens.closeDimensionEditor();
await PageObjects.lens.configureDimension({
dimension: 'lnsXY_yDimensionPanel > lns-empty-dimension',
operation: 'avg',
field: 'bytes',
});
await PageObjects.lens.closeDimensionEditor();
await PageObjects.lens.configureDimension({
dimension: 'lnsXY_splitDimensionPanel > lns-empty-dimension',
operation: 'terms',
field: 'ip',
});
await PageObjects.lens.closeDimensionEditor();
await PageObjects.lens.save(title, saveAsNew, redirectToOrigin);
}

View file

@ -51,7 +51,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
await find.clickByButtonText('lnsXYvis');
await dashboardAddPanel.closeAddPanel();
await PageObjects.lens.goToTimeRange();
await clickInChart(5, 5); // hardcoded position of bar
await clickInChart(5, 5); // hardcoded position of bar, depends heavy on data and charts implementation
await retry.try(async () => {
await testSubjects.click('applyFiltersPopoverButton');
@ -68,5 +68,23 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
const hasIpFilter = await filterBar.hasFilter('ip', '97.220.3.248');
expect(hasIpFilter).to.be(true);
});
it('should be able to add filters by clicking in pie chart', async () => {
await PageObjects.common.navigateToApp('dashboard');
await PageObjects.dashboard.clickNewDashboard();
await dashboardAddPanel.clickOpenAddPanel();
await dashboardAddPanel.filterEmbeddableNames('lnsPieVis');
await find.clickByButtonText('lnsPieVis');
await dashboardAddPanel.closeAddPanel();
await PageObjects.lens.goToTimeRange();
await clickInChart(5, 5); // hardcoded position of the slice, depends heavy on data and charts implementation
await PageObjects.lens.assertExactText(
'[data-test-subj="embeddablePanelHeading-lnsPieVis"]',
'lnsPieVis'
);
const hasGeoDestFilter = await filterBar.hasFilter('geo.dest', 'LS');
expect(hasGeoDestFilter).to.be(true);
});
});
}

View file

@ -34,18 +34,21 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
operation: 'date_histogram',
field: '@timestamp',
});
await PageObjects.lens.closeDimensionEditor();
await PageObjects.lens.configureDimension({
dimension: 'lnsXY_yDimensionPanel > lns-empty-dimension',
operation: 'sum',
field: 'bytes',
});
await PageObjects.lens.closeDimensionEditor();
await PageObjects.lens.configureDimension({
dimension: 'lnsXY_splitDimensionPanel > lns-empty-dimension',
operation: 'terms',
field: 'geo.src',
});
await PageObjects.lens.closeDimensionEditor();
expect(await find.allByCssSelector('.echLegendItem')).to.have.length(2);
await PageObjects.lens.save('Afancilenstest');

View file

@ -8,20 +8,12 @@ import expect from '@kbn/expect';
import { FtrProviderContext } from '../../ftr_provider_context';
export default function ({ getService, getPageObjects }: FtrProviderContext) {
const PageObjects = getPageObjects(['visualize', 'lens']);
const PageObjects = getPageObjects(['visualize', 'lens', 'common']);
const find = getService('find');
const listingTable = getService('listingTable');
const testSubjects = getService('testSubjects');
describe('lens smokescreen tests', () => {
it('should allow editing saved visualizations', async () => {
await PageObjects.visualize.gotoVisualizationLandingPage();
await listingTable.searchForItemWithName('Artistpreviouslyknownaslens');
await PageObjects.lens.clickVisualizeListItemTitle('Artistpreviouslyknownaslens');
await PageObjects.lens.goToTimeRange();
await PageObjects.lens.assertMetric('Maximum of bytes', '19,986');
});
it('should allow creation of lens xy chart', async () => {
await PageObjects.visualize.navigateToNewVisualization();
await PageObjects.visualize.clickVisType('lens');
@ -32,18 +24,21 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
operation: 'date_histogram',
field: '@timestamp',
});
await PageObjects.lens.closeDimensionEditor();
await PageObjects.lens.configureDimension({
dimension: 'lnsXY_yDimensionPanel > lns-empty-dimension',
operation: 'avg',
field: 'bytes',
});
await PageObjects.lens.closeDimensionEditor();
await PageObjects.lens.configureDimension({
dimension: 'lnsXY_splitDimensionPanel > lns-empty-dimension',
operation: 'terms',
field: '@message.raw',
});
await PageObjects.lens.closeDimensionEditor();
await PageObjects.lens.switchToVisualization('lnsDatatable');
await PageObjects.lens.removeDimension('lnsDatatable_column');
@ -54,6 +49,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
operation: 'terms',
field: 'ip',
});
await PageObjects.lens.closeDimensionEditor();
await PageObjects.lens.save('Afancilenstest');
@ -70,8 +66,23 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
// legend item(s), so we're using a class selector here.
expect(await find.allByCssSelector('.echLegendItem')).to.have.length(3);
});
it('should create an xy visualization with filters aggregation', async () => {
await PageObjects.visualize.gotoVisualizationLandingPage();
await listingTable.searchForItemWithName('lnsXYvis');
await PageObjects.lens.clickVisualizeListItemTitle('lnsXYvis');
await PageObjects.lens.goToTimeRange();
await PageObjects.lens.configureDimension({
dimension: 'lnsXY_splitDimensionPanel > lns-dimensionTrigger',
operation: 'filters',
isPreviousIncompatible: true,
});
await PageObjects.lens.addFilterToAgg(`geo.src : CN`);
it('should allow seamless transition to and from table view', async () => {
expect(await PageObjects.lens.getFiltersAggLabels()).to.eql([`ip : *`, `geo.src : CN`]);
expect(await find.allByCssSelector('.echLegendItem')).to.have.length(2);
});
it('should transition from metric to table to metric', async () => {
await PageObjects.visualize.gotoVisualizationLandingPage();
await listingTable.searchForItemWithName('Artistpreviouslyknownaslens');
await PageObjects.lens.clickVisualizeListItemTitle('Artistpreviouslyknownaslens');
@ -84,7 +95,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
await PageObjects.lens.assertMetric('Maximum of bytes', '19,986');
});
it('should switch from a multi-layer stacked bar to a multi-layer line chart', async () => {
it('should transition from a multi-layer stacked bar to a multi-layer line chart and correctly remove all layers', async () => {
await PageObjects.visualize.navigateToNewVisualization();
await PageObjects.visualize.clickVisType('lens');
await PageObjects.lens.goToTimeRange();
@ -95,22 +106,75 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
field: '@timestamp',
});
await PageObjects.lens.closeDimensionEditor();
await PageObjects.lens.configureDimension({
dimension: 'lnsXY_yDimensionPanel > lns-empty-dimension',
operation: 'avg',
field: 'bytes',
});
await PageObjects.lens.closeDimensionEditor();
await PageObjects.lens.createLayer();
expect(await PageObjects.lens.hasChartSwitchWarning('line')).to.eql(false);
await PageObjects.lens.switchToVisualization('line');
await PageObjects.lens.configureDimension(
{
dimension: 'lnsXY_xDimensionPanel > lns-empty-dimension',
operation: 'terms',
field: 'geo.src',
},
1
);
await PageObjects.lens.closeDimensionEditor();
await PageObjects.lens.configureDimension(
{
dimension: 'lnsXY_yDimensionPanel > lns-empty-dimension',
operation: 'avg',
field: 'bytes',
},
1
);
await PageObjects.lens.closeDimensionEditor();
expect(await PageObjects.lens.getLayerCount()).to.eql(2);
await testSubjects.click('lnsLayerRemove');
await testSubjects.click('lnsLayerRemove');
await testSubjects.existOrFail('empty-workspace');
});
it('should switch from a multi-layer stacked bar to donut chart using suggestions', async () => {
it('should edit settings of xy line chart', async () => {
await PageObjects.visualize.gotoVisualizationLandingPage();
await listingTable.searchForItemWithName('lnsXYvis');
await PageObjects.lens.clickVisualizeListItemTitle('lnsXYvis');
await PageObjects.lens.goToTimeRange();
await testSubjects.click('lnsXY_splitDimensionPanel > indexPattern-dimension-remove');
await PageObjects.lens.switchToVisualization('line');
await PageObjects.lens.configureDimension({
dimension: 'lnsXY_yDimensionPanel > lns-dimensionTrigger',
operation: 'max',
field: 'memory',
});
await PageObjects.lens.editDimensionLabel('Test of label');
await PageObjects.lens.editDimensionFormat('Percent');
await PageObjects.lens.editDimensionColor('#ff0000');
await PageObjects.lens.editMissingValues('Linear');
await PageObjects.lens.assertMissingValues('Linear');
await PageObjects.lens.assertColor('#ff0000');
await testSubjects.existOrFail('indexPattern-dimension-formatDecimals');
await PageObjects.lens.closeDimensionEditor();
expect(await PageObjects.lens.getDimensionTriggerText('lnsXY_yDimensionPanel')).to.eql(
'Test of label'
);
});
it('should transition from a multi-layer stacked bar to donut chart using suggestions', async () => {
await PageObjects.visualize.navigateToNewVisualization();
await PageObjects.visualize.clickVisType('lens');
await PageObjects.lens.goToTimeRange();
@ -121,12 +185,14 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
field: 'geo.dest',
});
await PageObjects.lens.closeDimensionEditor();
await PageObjects.lens.configureDimension({
dimension: 'lnsXY_yDimensionPanel > lns-empty-dimension',
operation: 'avg',
field: 'bytes',
});
await PageObjects.lens.closeDimensionEditor();
await PageObjects.lens.createLayer();
await PageObjects.lens.configureDimension(
@ -138,6 +204,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
1
);
await PageObjects.lens.closeDimensionEditor();
await PageObjects.lens.configureDimension(
{
dimension: 'lnsXY_yDimensionPanel > lns-empty-dimension',
@ -146,6 +213,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
},
1
);
await PageObjects.lens.closeDimensionEditor();
await PageObjects.lens.save('twolayerchart');
await testSubjects.click('lnsSuggestion-asDonut > lnsSuggestion');
@ -158,7 +227,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
);
});
it('should allow transition from line chart to donut chart and to bar chart', async () => {
it('should transition from line chart to donut chart and to bar chart', async () => {
await PageObjects.visualize.gotoVisualizationLandingPage();
await listingTable.searchForItemWithName('lnsXYvis');
await PageObjects.lens.clickVisualizeListItemTitle('lnsXYvis');
@ -185,7 +254,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
);
});
it('should allow seamless transition from bar chart to line chart using layer chart switch', async () => {
it('should transition from bar chart to line chart using layer chart switch', async () => {
await PageObjects.visualize.gotoVisualizationLandingPage();
await listingTable.searchForItemWithName('lnsXYvis');
await PageObjects.lens.clickVisualizeListItemTitle('lnsXYvis');
@ -203,7 +272,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
);
});
it('should allow seamless transition from pie chart to treemap chart', async () => {
it('should transition from pie chart to treemap chart', async () => {
await PageObjects.visualize.gotoVisualizationLandingPage();
await listingTable.searchForItemWithName('lnsPieVis');
await PageObjects.lens.clickVisualizeListItemTitle('lnsPieVis');
@ -221,7 +290,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
);
});
it('should allow creating a pie chart and switching to datatable', async () => {
it('should create a pie chart and switch to datatable', async () => {
await PageObjects.visualize.navigateToNewVisualization();
await PageObjects.visualize.clickVisType('lens');
await PageObjects.lens.goToTimeRange();
@ -231,6 +300,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
operation: 'date_histogram',
field: '@timestamp',
});
await PageObjects.lens.closeDimensionEditor();
await PageObjects.lens.configureDimension({
dimension: 'lnsPie_sizeByDimensionPanel > lns-empty-dimension',
@ -238,6 +308,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
field: 'bytes',
});
await PageObjects.lens.closeDimensionEditor();
expect(await PageObjects.lens.hasChartSwitchWarning('lnsDatatable')).to.eql(false);
await PageObjects.lens.switchToVisualization('lnsDatatable');

View file

@ -13,7 +13,7 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont
const retry = getService('retry');
const find = getService('find');
const comboBox = getService('comboBox');
const PageObjects = getPageObjects(['header', 'header', 'timePicker']);
const PageObjects = getPageObjects(['header', 'header', 'timePicker', 'common']);
return logWrapper('lensPage', log, {
/**
@ -85,19 +85,32 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont
* @param layerIndex - the index of the layer
*/
async configureDimension(
opts: { dimension: string; operation: string; field: string },
opts: {
dimension: string;
operation: string;
field?: string;
isPreviousIncompatible?: boolean;
},
layerIndex = 0
) {
await retry.try(async () => {
await testSubjects.click(`lns-layerPanel-${layerIndex} > ${opts.dimension}`);
await testSubjects.exists(`lns-indexPatternDimension-${opts.operation}`);
});
const operationSelector = opts.isPreviousIncompatible
? `lns-indexPatternDimension-${opts.operation} incompatible`
: `lns-indexPatternDimension-${opts.operation}`;
await testSubjects.click(operationSelector);
await testSubjects.click(`lns-indexPatternDimension-${opts.operation}`);
if (opts.field) {
const target = await testSubjects.find('indexPattern-dimension-field');
await comboBox.openOptionsList(target);
await comboBox.setElement(target, opts.field);
}
},
const target = await testSubjects.find('indexPattern-dimension-field');
await comboBox.openOptionsList(target);
await comboBox.setElement(target, opts.field);
// closes the dimension editor flyout
async closeDimensionEditor() {
await testSubjects.click('lns-indexPattern-dimensionContainerTitle');
},
@ -107,7 +120,17 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont
async removeDimension(dimensionTestSubj: string) {
await testSubjects.click(`${dimensionTestSubj} > indexPattern-dimension-remove`);
},
/**
* adds new filter to filters agg
*/
async addFilterToAgg(queryString: string) {
await testSubjects.click('lns-newBucket-add');
const queryInput = await testSubjects.find('indexPattern-filters-queryStringInput');
await queryInput.type(queryString);
await PageObjects.common.pressEnterKey();
await PageObjects.common.pressEnterKey();
await PageObjects.common.sleep(1000); // give time for debounced components to rerender
},
/**
* Save the current Lens visualization.
*/
@ -141,10 +164,43 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont
await testSubjects.click('lnsApp_saveAndReturnButton');
},
async editDimensionLabel(label: string) {
await testSubjects.setValue('indexPattern-label-edit', label);
},
async editDimensionFormat(format: string) {
const formatInput = await testSubjects.find('indexPattern-dimension-format');
await comboBox.openOptionsList(formatInput);
await comboBox.setElement(formatInput, format);
},
async editDimensionColor(color: string) {
const colorPickerInput = await testSubjects.find('colorPickerAnchor');
await colorPickerInput.type(color);
await PageObjects.common.sleep(1000); // give time for debounced components to rerender
},
async editMissingValues(option: string) {
await retry.try(async () => {
await testSubjects.click('lnsMissingValuesButton');
await testSubjects.exists('lnsMissingValuesSelect');
});
await testSubjects.click('lnsMissingValuesSelect');
const optionSelector = await find.byCssSelector(`#${option}`);
await optionSelector.click();
},
getTitle() {
return testSubjects.getVisibleText('lns_ChartTitle');
},
async getFiltersAggLabels() {
const labels = [];
const filters = await testSubjects.findAll('indexPattern-filters-existingFilterContainer');
for (let i = 0; i < filters.length; i++) {
labels.push(await filters[i].getVisibleText());
}
log.debug(`Found ${labels.length} filters on current page`);
return labels;
},
/**
* Uses the Lens visualization switcher to switch visualizations.
*
@ -275,5 +331,13 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont
await this.assertExactText('[data-test-subj="lns_metric_title"]', title);
await this.assertExactText('[data-test-subj="lns_metric_value"]', count);
},
async assertMissingValues(option: string) {
await this.assertExactText('[data-test-subj="lnsMissingValuesSelect"]', option);
},
async assertColor(color: string) {
// TODO: target dimensionTrigger color element after merging https://github.com/elastic/kibana/pull/76871
await testSubjects.getAttribute('colorPickerAnchor', color);
},
});
}