Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ftr] migrate "listingTable" service to FtrService class #100606

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions test/functional/services/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ import {
ElasticChartProvider,
VegaDebugInspectorViewProvider,
} from './visualizations';
import { ListingTableProvider } from './listing_table';
import { ListingTableService } from './listing_table';
import { SavedQueryManagementComponentProvider } from './saved_query_management_component';
import { KibanaSupertestProvider } from './supertest';
import { MenuToggleProvider } from './menu_toggle';
Expand All @@ -63,7 +63,7 @@ export const services = {
dashboardVisualizations: DashboardVisualizationProvider,
dashboardExpect: DashboardExpectProvider,
failureDebugging: FailureDebuggingProvider,
listingTable: ListingTableProvider,
listingTable: ListingTableService,
dashboardAddPanel: DashboardAddPanelProvider,
dashboardReplacePanel: DashboardReplacePanelProvider,
dashboardPanelActions: DashboardPanelActionsProvider,
Expand Down
339 changes: 168 additions & 171 deletions test/functional/services/listing_table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,202 +7,199 @@
*/

import expect from '@kbn/expect';
import { FtrProviderContext } from '../ftr_provider_context';
import { FtrService } from '../ftr_provider_context';

type AppName = 'visualize' | 'dashboard' | 'map';
type AppName = keyof typeof PREFIX_MAP;
const PREFIX_MAP = { visualize: 'vis', dashboard: 'dashboard', map: 'map' };

export function ListingTableProvider({ getService, getPageObjects }: FtrProviderContext) {
const testSubjects = getService('testSubjects');
const find = getService('find');
const log = getService('log');
const retry = getService('retry');
const { common, header } = getPageObjects(['common', 'header']);
const prefixMap = { visualize: 'vis', dashboard: 'dashboard', map: 'map' };
export class ListingTableService extends FtrService {
private readonly testSubjects = this.ctx.getService('testSubjects');
private readonly find = this.ctx.getService('find');
private readonly log = this.ctx.getService('log');
private readonly retry = this.ctx.getService('retry');
private readonly common = this.ctx.getPageObjects(['common']).common;
private readonly header = this.ctx.getPageObjects(['header']).header;

class ListingTable {
private async getSearchFilter() {
return await testSubjects.find('tableListSearchBox');
}
private async getSearchFilter() {
return await this.testSubjects.find('tableListSearchBox');
}

/**
* Returns search input value on landing page
*/
public async getSearchFilterValue() {
const searchFilter = await this.getSearchFilter();
return await searchFilter.getAttribute('value');
}
/**
* Returns search input value on landing page
*/
public async getSearchFilterValue() {
const searchFilter = await this.getSearchFilter();
return await searchFilter.getAttribute('value');
}

/**
* Clears search input on landing page
*/
public async clearSearchFilter() {
const searchFilter = await this.getSearchFilter();
await searchFilter.clearValue();
await searchFilter.click();
}
/**
* Clears search input on landing page
*/
public async clearSearchFilter() {
const searchFilter = await this.getSearchFilter();
await searchFilter.clearValue();
await searchFilter.click();
}

private async getAllItemsNamesOnCurrentPage(): Promise<string[]> {
const visualizationNames = [];
const links = await find.allByCssSelector('.euiTableRow .euiLink');
for (let i = 0; i < links.length; i++) {
visualizationNames.push(await links[i].getVisibleText());
}
log.debug(`Found ${visualizationNames.length} visualizations on current page`);
return visualizationNames;
private async getAllItemsNamesOnCurrentPage(): Promise<string[]> {
const visualizationNames = [];
const links = await this.find.allByCssSelector('.euiTableRow .euiLink');
for (let i = 0; i < links.length; i++) {
visualizationNames.push(await links[i].getVisibleText());
}
this.log.debug(`Found ${visualizationNames.length} visualizations on current page`);
return visualizationNames;
}

public async waitUntilTableIsLoaded() {
return retry.try(async () => {
const isLoaded = await find.existsByDisplayedByCssSelector(
'[data-test-subj="itemsInMemTable"]:not(.euiBasicTable-loading)'
);

if (isLoaded) {
return true;
} else {
throw new Error('Waiting');
}
});
}
public async waitUntilTableIsLoaded() {
return this.retry.try(async () => {
const isLoaded = await this.find.existsByDisplayedByCssSelector(
'[data-test-subj="itemsInMemTable"]:not(.euiBasicTable-loading)'
);

/**
* Navigates through all pages on Landing page and returns array of items names
*/
public async getAllItemsNames(): Promise<string[]> {
log.debug('ListingTable.getAllItemsNames');
let morePages = true;
let visualizationNames: string[] = [];
while (morePages) {
visualizationNames = visualizationNames.concat(await this.getAllItemsNamesOnCurrentPage());
morePages = !(
(await testSubjects.getAttribute('pagination-button-next', 'disabled')) === 'true'
);
if (morePages) {
await testSubjects.click('pagerNextButton');
await header.waitUntilLoadingHasFinished();
}
if (isLoaded) {
return true;
} else {
throw new Error('Waiting');
}
return visualizationNames;
}
});
}

/**
* Returns items count on landing page
*/
public async expectItemsCount(appName: AppName, count: number) {
await retry.try(async () => {
const elements = await find.allByCssSelector(
`[data-test-subj^="${prefixMap[appName]}ListingTitleLink"]`
);
expect(elements.length).to.equal(count);
});
/**
* Navigates through all pages on Landing page and returns array of items names
*/
public async getAllItemsNames(): Promise<string[]> {
this.log.debug('ListingTable.getAllItemsNames');
let morePages = true;
let visualizationNames: string[] = [];
while (morePages) {
visualizationNames = visualizationNames.concat(await this.getAllItemsNamesOnCurrentPage());
morePages = !(
(await this.testSubjects.getAttribute('pagination-button-next', 'disabled')) === 'true'
);
if (morePages) {
await this.testSubjects.click('pagerNextButton');
await this.header.waitUntilLoadingHasFinished();
}
}
return visualizationNames;
}

/**
* Types name into search field on Landing page and waits till search completed
* @param name item name
*/
public async searchForItemWithName(name: string, { escape = true }: { escape?: boolean } = {}) {
log.debug(`searchForItemWithName: ${name}`);

await retry.try(async () => {
const searchFilter = await this.getSearchFilter();
await searchFilter.clearValue();
await searchFilter.click();

if (escape) {
name = name
// Note: this replacement of - to space is to preserve original logic but I'm not sure why or if it's needed.
.replace('-', ' ')
// Remove `[*]` from search as it is not supported by EUI Query's syntax.
.replace(/ *\[[^)]*\] */g, '');
}

await searchFilter.type(name);
await common.pressEnterKey();
});
/**
* Returns items count on landing page
*/
public async expectItemsCount(appName: AppName, count: number) {
await this.retry.try(async () => {
const elements = await this.find.allByCssSelector(
`[data-test-subj^="${PREFIX_MAP[appName]}ListingTitleLink"]`
);
expect(elements.length).to.equal(count);
});
}

await header.waitUntilLoadingHasFinished();
}
/**
* Types name into search field on Landing page and waits till search completed
* @param name item name
*/
public async searchForItemWithName(name: string, { escape = true }: { escape?: boolean } = {}) {
this.log.debug(`searchForItemWithName: ${name}`);

/**
* Searches for item on Landing page and retruns items count that match `ListingTitleLink-${name}` pattern
*/
public async searchAndExpectItemsCount(appName: AppName, name: string, count: number) {
await this.searchForItemWithName(name);
await retry.try(async () => {
const links = await testSubjects.findAll(
`${prefixMap[appName]}ListingTitleLink-${name.replace(/ /g, '-')}`
);
expect(links.length).to.equal(count);
});
}
await this.retry.try(async () => {
const searchFilter = await this.getSearchFilter();
await searchFilter.clearValue();
await searchFilter.click();

public async clickDeleteSelected() {
await testSubjects.click('deleteSelectedItems');
}
if (escape) {
name = name
// Note: this replacement of - to space is to preserve original logic but I'm not sure why or if it's needed.
.replace('-', ' ')
// Remove `[*]` from search as it is not supported by EUI Query's syntax.
.replace(/ *\[[^)]*\] */g, '');
}

public async clickItemCheckbox(id: string) {
await testSubjects.click(`checkboxSelectRow-${id}`);
}
await searchFilter.type(name);
await this.common.pressEnterKey();
});

/**
* Searches for item by name, selects checbox and deletes it
* @param name item name
* @param id row id
*/
public async deleteItem(name: string, id: string) {
await this.searchForItemWithName(name);
await this.clickItemCheckbox(id);
await this.clickDeleteSelected();
await common.clickConfirmOnModal();
}
await this.header.waitUntilLoadingHasFinished();
}

/**
* Clicks item on Landing page by link name if it is present
*/
public async clickItemLink(appName: AppName, name: string) {
await testSubjects.click(
`${prefixMap[appName]}ListingTitleLink-${name.split(' ').join('-')}`
/**
* Searches for item on Landing page and retruns items count that match `ListingTitleLink-${name}` pattern
*/
public async searchAndExpectItemsCount(appName: AppName, name: string, count: number) {
await this.searchForItemWithName(name);
await this.retry.try(async () => {
const links = await this.testSubjects.findAll(
`${PREFIX_MAP[appName]}ListingTitleLink-${name.replace(/ /g, '-')}`
);
}
expect(links.length).to.equal(count);
});
}

/**
* Checks 'SelectAll' checkbox on
*/
public async checkListingSelectAllCheckbox() {
const element = await testSubjects.find('checkboxSelectAll');
const isSelected = await element.isSelected();
if (!isSelected) {
log.debug(`checking checkbox "checkboxSelectAll"`);
await testSubjects.click('checkboxSelectAll');
}
}
public async clickDeleteSelected() {
await this.testSubjects.click('deleteSelectedItems');
}

/**
* Clicks NewItem button on Landing page
* @param promptBtnTestSubj testSubj locator for Prompt button
*/
public async clickNewButton(promptBtnTestSubj: string): Promise<void> {
await retry.tryForTime(20000, async () => {
// newItemButton button is only visible when there are items in the listing table is displayed.
const isnNewItemButtonPresent = await testSubjects.exists('newItemButton', {
timeout: 10000,
});
if (isnNewItemButtonPresent) {
await testSubjects.click('newItemButton');
} else {
// no items exist, click createPromptButton to create new dashboard/visualization
await testSubjects.click(promptBtnTestSubj);
}
});
public async clickItemCheckbox(id: string) {
await this.testSubjects.click(`checkboxSelectRow-${id}`);
}

/**
* Searches for item by name, selects checbox and deletes it
* @param name item name
* @param id row id
*/
public async deleteItem(name: string, id: string) {
await this.searchForItemWithName(name);
await this.clickItemCheckbox(id);
await this.clickDeleteSelected();
await this.common.clickConfirmOnModal();
}

/**
* Clicks item on Landing page by link name if it is present
*/
public async clickItemLink(appName: AppName, name: string) {
await this.testSubjects.click(
`${PREFIX_MAP[appName]}ListingTitleLink-${name.split(' ').join('-')}`
);
}

/**
* Checks 'SelectAll' checkbox on
*/
public async checkListingSelectAllCheckbox() {
const element = await this.testSubjects.find('checkboxSelectAll');
const isSelected = await element.isSelected();
if (!isSelected) {
this.log.debug(`checking checkbox "checkboxSelectAll"`);
await this.testSubjects.click('checkboxSelectAll');
}
}

public async onListingPage(appName: AppName) {
return await testSubjects.exists(`${appName}LandingPage`, {
timeout: 5000,
/**
* Clicks NewItem button on Landing page
* @param promptBtnTestSubj testSubj locator for Prompt button
*/
public async clickNewButton(promptBtnTestSubj: string): Promise<void> {
await this.retry.tryForTime(20000, async () => {
// newItemButton button is only visible when there are items in the listing table is displayed.
const isnNewItemButtonPresent = await this.testSubjects.exists('newItemButton', {
timeout: 10000,
});
}
if (isnNewItemButtonPresent) {
await this.testSubjects.click('newItemButton');
} else {
// no items exist, click createPromptButton to create new dashboard/visualization
await this.testSubjects.click(promptBtnTestSubj);
}
});
}

return new ListingTable();
public async onListingPage(appName: AppName) {
return await this.testSubjects.exists(`${appName}LandingPage`, {
timeout: 5000,
});
}
}