kibana/test/functional/page_objects/management/saved_objects_page.ts
Spencer 4f4cf054de
[7.x] [ts] migrate root test dir to project refs (#99148) (#101416)
* [ts] migrate root test dir to project refs (#99148)

Co-authored-by: spalger <spalger@users.noreply.github.com>

* include schema files in telemetry ts project

Co-authored-by: spalger <spalger@users.noreply.github.com>
2021-06-04 16:22:00 -04:00

332 lines
13 KiB
TypeScript

/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import { keyBy } from 'lodash';
import { map as mapAsync } from 'bluebird';
import { FtrService } from '../../ftr_provider_context';
export class SavedObjectsPageObject extends FtrService {
private readonly log = this.ctx.getService('log');
private readonly retry = this.ctx.getService('retry');
private readonly browser = this.ctx.getService('browser');
private readonly find = this.ctx.getService('find');
private readonly testSubjects = this.ctx.getService('testSubjects');
private readonly common = this.ctx.getPageObject('common');
private readonly header = this.ctx.getPageObject('header');
async searchForObject(objectName: string) {
const searchBox = await this.testSubjects.find('savedObjectSearchBar');
await searchBox.clearValue();
await searchBox.type(objectName);
await searchBox.pressKeys(this.browser.keys.ENTER);
await this.header.waitUntilLoadingHasFinished();
await this.waitTableIsLoaded();
}
async getCurrentSearchValue() {
const searchBox = await this.testSubjects.find('savedObjectSearchBar');
return await searchBox.getAttribute('value');
}
async importFile(path: string, overwriteAll = true) {
this.log.debug(`importFile(${path})`);
this.log.debug(`Clicking importObjects`);
await this.testSubjects.click('importObjects');
await this.common.setFileInputPath(path);
if (!overwriteAll) {
this.log.debug(`Toggling overwriteAll`);
const radio = await this.testSubjects.find(
'savedObjectsManagement-importModeControl-overwriteRadioGroup'
);
// a radio button consists of a div tag that contains an input, a div, and a label
// we can't click the input directly, need to go up one level and click the parent div
const div = await radio.findByXpath("//div[input[@id='overwriteDisabled']]");
await div.click();
} else {
this.log.debug(`Leaving overwriteAll alone`);
}
await this.testSubjects.click('importSavedObjectsImportBtn');
this.log.debug(`done importing the file`);
// Wait for all the saves to happen
await this.header.waitUntilLoadingHasFinished();
}
async checkImportSucceeded() {
await this.testSubjects.existOrFail('importSavedObjectsSuccess', { timeout: 20000 });
}
async checkNoneImported() {
await this.testSubjects.existOrFail('importSavedObjectsSuccessNoneImported', {
timeout: 20000,
});
}
async checkImportConflictsWarning() {
await this.testSubjects.existOrFail('importSavedObjectsConflictsWarning', { timeout: 20000 });
}
async checkImportLegacyWarning() {
await this.testSubjects.existOrFail('importSavedObjectsLegacyWarning', { timeout: 20000 });
}
async checkImportFailedWarning() {
await this.testSubjects.existOrFail('importSavedObjectsFailedWarning', { timeout: 20000 });
}
async checkImportError() {
await this.testSubjects.existOrFail('importSavedObjectsErrorText', { timeout: 20000 });
}
async getImportErrorText() {
return await this.testSubjects.getVisibleText('importSavedObjectsErrorText');
}
async clickImportDone() {
await this.testSubjects.click('importSavedObjectsDoneBtn');
await this.waitTableIsLoaded();
}
async clickConfirmChanges() {
await this.testSubjects.click('importSavedObjectsConfirmBtn');
}
async waitTableIsLoaded() {
return this.retry.try(async () => {
const isLoaded = await this.find.existsByDisplayedByCssSelector(
'*[data-test-subj="savedObjectsTable"] :not(.euiBasicTable-loading)'
);
if (isLoaded) {
return true;
} else {
throw new Error('Waiting');
}
});
}
async clickRelationshipsByTitle(title: string) {
const table = keyBy(await this.getElementsInTable(), 'title');
// should we check if table size > 0 and log error if not?
if (table[title].menuElement) {
this.log.debug(`we found a context menu element for (${title}) so click it`);
await table[title].menuElement?.click();
// Wait for context menu to render
const menuPanel = await this.find.byCssSelector('.euiContextMenuPanel');
await (await menuPanel.findByTestSubject('savedObjectsTableAction-relationships')).click();
} else {
this.log.debug(
`we didn't find a menu element so should be a relastionships element for (${title}) to click`
);
// or the action elements are on the row without the menu
await table[title].relationshipsElement?.click();
}
}
async setOverriddenIndexPatternValue(oldName: string, newName: string) {
const select = await this.testSubjects.find(`managementChangeIndexSelection-${oldName}`);
const option = await this.testSubjects.findDescendant(`indexPatternOption-${newName}`, select);
await option.click();
}
async clickCopyToSpaceByTitle(title: string) {
const table = keyBy(await this.getElementsInTable(), 'title');
// should we check if table size > 0 and log error if not?
if (table[title].menuElement) {
this.log.debug(`we found a context menu element for (${title}) so click it`);
await table[title].menuElement?.click();
// Wait for context menu to render
const menuPanel = await this.find.byCssSelector('.euiContextMenuPanel');
await (
await menuPanel.findByTestSubject('savedObjectsTableAction-copy_saved_objects_to_space')
).click();
} else {
this.log.debug(
`we didn't find a menu element so should be a "copy to space" element for (${title}) to click`
);
// or the action elements are on the row without the menu
await table[title].copySaveObjectsElement?.click();
}
}
async clickInspectByTitle(title: string) {
const table = keyBy(await this.getElementsInTable(), 'title');
if (table[title].menuElement) {
await table[title].menuElement?.click();
// Wait for context menu to render
const menuPanel = await this.find.byCssSelector('.euiContextMenuPanel');
const panelButton = await menuPanel.findByTestSubject('savedObjectsTableAction-inspect');
await panelButton.click();
} else {
// or the action elements are on the row without the menu
await table[title].copySaveObjectsElement?.click();
}
}
async clickCheckboxByTitle(title: string) {
const table = keyBy(await this.getElementsInTable(), 'title');
// should we check if table size > 0 and log error if not?
await table[title].checkbox.click();
}
async getObjectTypeByTitle(title: string) {
const table = keyBy(await this.getElementsInTable(), 'title');
// should we check if table size > 0 and log error if not?
return table[title].objectType;
}
async getElementsInTable() {
const rows = await this.testSubjects.findAll('~savedObjectsTableRow');
return mapAsync(rows, async (row) => {
const checkbox = await row.findByCssSelector('[data-test-subj*="checkboxSelectRow"]');
// return the object type aria-label="index patterns"
const objectType = await row.findByTestSubject('objectType');
const titleElement = await row.findByTestSubject('savedObjectsTableRowTitle');
// not all rows have inspect button - Advanced Settings objects don't
// Advanced Settings has 2 actions,
// data-test-subj="savedObjectsTableAction-relationships"
// data-test-subj="savedObjectsTableAction-copy_saved_objects_to_space"
// Some other objects have the ...
// data-test-subj="euiCollapsedItemActionsButton"
// Maybe some objects still have the inspect element visible?
// !!! Also note that since we don't have spaces on OSS, the actions for the same object can be different depending on OSS or not
let menuElement = null;
let inspectElement = null;
let relationshipsElement = null;
let copySaveObjectsElement = null;
const actions = await row.findByClassName('euiTableRowCell--hasActions');
// getting the innerHTML and checking if it 'includes' a string is faster than a timeout looking for each element
const actionsHTML = await actions.getAttribute('innerHTML');
if (actionsHTML.includes('euiCollapsedItemActionsButton')) {
menuElement = await row.findByTestSubject('euiCollapsedItemActionsButton');
}
if (actionsHTML.includes('savedObjectsTableAction-inspect')) {
inspectElement = await row.findByTestSubject('savedObjectsTableAction-inspect');
}
if (actionsHTML.includes('savedObjectsTableAction-relationships')) {
relationshipsElement = await row.findByTestSubject('savedObjectsTableAction-relationships');
}
if (actionsHTML.includes('savedObjectsTableAction-copy_saved_objects_to_space')) {
copySaveObjectsElement = await row.findByTestSubject(
'savedObjectsTableAction-copy_saved_objects_to_space'
);
}
return {
checkbox,
objectType: await objectType.getAttribute('aria-label'),
titleElement,
title: await titleElement.getVisibleText(),
menuElement,
inspectElement,
relationshipsElement,
copySaveObjectsElement,
};
});
}
async getRowTitles() {
await this.waitTableIsLoaded();
const table = await this.testSubjects.find('savedObjectsTable');
const $ = await table.parseDomContent();
return $.findTestSubjects('savedObjectsTableRowTitle')
.toArray()
.map((cell) => $(cell).find('.euiTableCellContent').text());
}
async getRelationshipFlyout() {
const rows = await this.testSubjects.findAll('relationshipsTableRow');
return mapAsync(rows, async (row) => {
const objectType = await row.findByTestSubject('relationshipsObjectType');
const relationship = await row.findByTestSubject('directRelationship');
const titleElement = await row.findByTestSubject('relationshipsTitle');
const inspectElement = await row.findByTestSubject('relationshipsTableAction-inspect');
return {
objectType: await objectType.getAttribute('aria-label'),
relationship: await relationship.getVisibleText(),
titleElement,
title: await titleElement.getVisibleText(),
inspectElement,
};
});
}
async getInvalidRelations() {
const rows = await this.testSubjects.findAll('invalidRelationshipsTableRow');
return mapAsync(rows, async (row) => {
const objectType = await row.findByTestSubject('relationshipsObjectType');
const objectId = await row.findByTestSubject('relationshipsObjectId');
const relationship = await row.findByTestSubject('directRelationship');
const error = await row.findByTestSubject('relationshipsError');
return {
type: await objectType.getVisibleText(),
id: await objectId.getVisibleText(),
relationship: await relationship.getVisibleText(),
error: await error.getVisibleText(),
};
});
}
async getTableSummary() {
const table = await this.testSubjects.find('savedObjectsTable');
const $ = await table.parseDomContent();
return $('tbody tr')
.toArray()
.map((row) => {
return {
title: $(row).find('td:nth-child(3) .euiTableCellContent').text(),
canViewInApp: Boolean($(row).find('td:nth-child(3) a').length),
};
});
}
async clickTableSelectAll() {
await this.testSubjects.click('checkboxSelectAll');
}
async canBeDeleted() {
return await this.testSubjects.isEnabled('savedObjectsManagementDelete');
}
async clickDelete({ confirmDelete = true }: { confirmDelete?: boolean } = {}) {
await this.testSubjects.click('savedObjectsManagementDelete');
if (confirmDelete) {
await this.testSubjects.click('confirmModalConfirmButton');
await this.waitTableIsLoaded();
}
}
async getImportWarnings() {
const elements = await this.testSubjects.findAll('importSavedObjectsWarning');
return Promise.all(
elements.map(async (element) => {
const message = await element
.findByClassName('euiCallOutHeader__title')
.then((titleEl) => titleEl.getVisibleText());
const buttons = await element.findAllByClassName('euiButton');
return {
message,
type: buttons.length ? 'action_required' : 'simple',
};
})
);
}
async getImportErrorsCount() {
this.log.debug(`Toggling overwriteAll`);
const errorCountNode = await this.testSubjects.find('importSavedObjectsErrorsCount');
const errorCountText = await errorCountNode.getVisibleText();
const match = errorCountText.match(/(\d)+/);
if (!match) {
throw Error(`unable to parse error count from text ${errorCountText}`);
}
return +match[1];
}
}