/*********************************************************************
 * Copyright (c) 2019 Red Hat, Inc.
 *
 * This program and the accompanying materials are made
 * available under the terms of the Eclipse Public License 2.0
 * which is available at https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 **********************************************************************/ import { injectable , inject } from 'inversify' ; import { CLASSES } from '../../inversify.types' ; import { DriverHelper } from '../../utils/DriverHelper' ; import { By , Key , WebElement , error } from 'selenium-webdriver' ; import { Logger } from '../../utils/Logger' ; import { TimeoutConstants } from '../../TimeoutConstants' ; import { TestConstants } from '../../TestConstants' ; @ injectable ( ) export class Terminal { constructor ( @ inject ( CLASSES . DriverHelper ) private readonly driverHelper ) { } async waitTab ( tabTitle , timeout = TimeoutConstants . TS_SELENIUM_TERMINAL_DEFAULT_TIMEOUT ) { Logger . debug ( `Terminal.waitTab "${ tabTitle }"` ) ; const terminalTabLocator = By . css ( this . getTerminalTabCssLocator ( tabTitle ) ) ; await this . driverHelper . waitVisibility ( terminalTabLocator , timeout ) ; } async waitTabAbsence ( tabTitle , timeout = TimeoutConstants . TS_SELENIUM_TERMINAL_DEFAULT_TIMEOUT ) { Logger . debug ( `Terminal.waitTabAbsence "${ tabTitle }"` ) ; const terminalTabLocator = By . css ( this . getTerminalTabCssLocator ( tabTitle ) ) ; await this . driverHelper . waitDisappearanceWithTimeout ( terminalTabLocator , timeout ) ; } async clickOnTab ( tabTitle , timeout = TimeoutConstants . TS_SELENIUM_TERMINAL_DEFAULT_TIMEOUT ) { Logger . debug ( `Terminal.clickOnTab "${ tabTitle }"` ) ; const terminalTabLocator = By . css ( `${ this . getTerminalTabCssLocator ( tabTitle ) } div.theia-tab-icon-label` ) ; await this , this . driverHelper . waitAndClick ( terminalTabLocator , timeout ) ; } async waitTabFocused ( tabTitle , timeout = TimeoutConstants . TS_SELENIUM_TERMINAL_DEFAULT_TIMEOUT ) { Logger . debug ( `Terminal.waitTabFocused "${ tabTitle }"` ) ; const focusedTerminalTabLocator = this . getFocusedTerminalTabLocator ( tabTitle ) ; await this . driverHelper . waitVisibility ( focusedTerminalTabLocator , timeout ) ; } async selectTerminalTab ( tabTitle , timeout = TimeoutConstants . TS_SELENIUM_TERMINAL_DEFAULT_TIMEOUT ) { Logger . debug ( `Terminal.selectTerminalTab "${ tabTitle }"` ) ; await this . clickOnTab ( tabTitle , timeout ) ; await this . waitTabFocused ( tabTitle , timeout ) ; } async clickOnTabCloseIcon ( tabTitle , timeout = TimeoutConstants . TS_SELENIUM_TERMINAL_DEFAULT_TIMEOUT ) { Logger . debug ( `Terminal.clickOnTabCloseIcon "${ tabTitle }"` ) ; const terminalTabCloseIconLocator = By . css ( `${ this . getTerminalTabCssLocator ( tabTitle ) } div.p-TabBar-tabCloseIcon` ) ; await this . driverHelper . waitAndClick ( terminalTabCloseIconLocator , timeout ) ; } async closeTerminalTab ( tabTitle , timeout = TimeoutConstants . TS_SELENIUM_TERMINAL_DEFAULT_TIMEOUT ) { Logger . debug ( `Terminal.closeTerminalTab "${ tabTitle }"` ) ; await this . clickOnTabCloseIcon ( tabTitle , timeout ) ; await this . waitTabAbsence ( tabTitle , timeout ) ; } async type ( terminalTabTitle , text ) { Logger . debug ( `Terminal.type "${ terminalTabTitle }"` ) ; const terminalID = await this . getTerminalID ( terminalTabTitle ) ; const terminalInteractionContainer = this . getTerminalEditorInteractionEditorLocator ( terminalID ) ; await this . driverHelper . typeToInvisible ( terminalInteractionContainer , text ) ; } async rejectTerminalProcess ( tabTitle , timeout = TimeoutConstants . TS_SELENIUM_TERMINAL_DEFAULT_TIMEOUT ) { Logger . debug ( `Terminal.rejectTerminalProcess "${ tabTitle }"` ) ; await this . selectTerminalTab ( tabTitle , timeout ) ; await this . type ( tabTitle , Key . chord ( Key . CONTROL , 'c' ) ) ; } async getText ( terminalTab , timeout = TimeoutConstants . TS_SELENIUM_TERMINAL_DEFAULT_TIMEOUT ) { Logger . debug ( `Terminal.getText tab: ${ terminalTab }` ) ; const terminalID = await this . getTerminalID ( terminalTab ) ; const terminalRowsLocator = this . getTerminalEditorTerminalRowsLocator ( terminalID ) ; await this . selectTerminalTab ( terminalTab , timeout ) ; return await this . driverHelper . waitAndGetText ( terminalRowsLocator , timeout ) ; } async getTextFromProblemsTab ( timeout = TimeoutConstants . TS_SELENIUM_TERMINAL_DEFAULT_TIMEOUT ) { Logger . debug ( `Terminal.getTextFromProblemsTab` ) ; const problemsTabBodyLocator = By . xpath ( `//div[@id='problems']` ) ; return await this . driverHelper . waitAndGetText ( problemsTabBodyLocator , timeout ) ; } async selectTabByPrefixAndWaitText ( terminalTab , expectedText , timeout = TimeoutConstants . TS_SELENIUM_TERMINAL_DEFAULT_TIMEOUT ) { Logger . debug ( `Terminal.selectTabByPrefixAndWaitText tab: ${ terminalTab } text: ${ expectedText }` ) ; const terminalTabLocatorWithPreffix = `//li[contains(@title, '${ terminalTab }')]` ; const terminalID = await this . getTerminalID ( terminalTab ) ; const terminalRowsLocator = this . getTerminalEditorTerminalRowsLocator ( terminalID ) ; await this . driverHelper . waitAndClick ( By . xpath ( terminalTabLocatorWithPreffix ) , timeout ) ; await this . driverHelper . waitUntilTrue ( async ( ) => { const terminalText = await this . driverHelper . waitAndGetText ( terminalRowsLocator , timeout ) ; return terminalText . includes ( expectedText ) ; } , timeout ) ; } async waitText ( terminalTab , expectedText , timeout ) { Logger . debug ( `Terminal.waitText tab: ${ terminalTab } text: ${ expectedText }` ) ; await this . selectTerminalTab ( terminalTab , timeout ) ; await this . driverHelper . waitUntilTrue ( async ( ) => { Logger . debug ( '----------------------------------------------' ) ; const terminalText = await this . getText ( terminalTab , timeout ) ; if ( terminalText . includes ( expectedText ) ) { Logger . debug ( 'Expected text is present in the terminal output' ) ; return true ; } Logger . debug ( 'Expected text is not present in the terminal output' ) ; await this . driverHelper . wait ( 1000 ) ; return false ; } , timeout ) ; } async waitTextInProblemsTab ( expectedText , timeout ) { Logger . debug ( `Terminal.waitTextInProblemsTab` ) ; await this . selectTerminalTab ( 'Problems' , timeout ) ; await this . driverHelper . waitUntilTrue ( async ( ) => { Logger . debug ( '----------------------------------------------' ) ; const terminalText = await this . getTextFromProblemsTab ( timeout ) ; if ( terminalText . includes ( expectedText ) ) { Logger . debug ( 'Expected text is present in the terminal output' ) ; return true ; } Logger . debug ( 'Expected text is not present in the terminal output' ) ; await this . driverHelper . wait ( 1000 ) ; return false ; } , timeout ) ; } public async waitIconSuccess ( taskName , timeout ) { const terminalTabLocator = By . css ( `${ this . getTerminalTabCssLocator ( taskName ) } div.p-TabBar-tabIcon` ) ; await this . driverHelper . waitVisibility ( terminalTabLocator , TimeoutConstants . TS_SELENIUM_TERMINAL_DEFAULT_TIMEOUT ) ; let terminalClass = await this . driverHelper . waitAndGetElementAttribute ( terminalTabLocator , 'class' ) ; await this . driverHelper . getDriver ( ) . wait ( async ( ) => { terminalClass = await this . driverHelper . waitAndGetElementAttribute ( terminalTabLocator , 'class' ) ; if ( terminalClass . includes ( 'fa-check' ) ) { return true ; } if ( terminalClass . includes ( 'fa-times-circle' ) ) { Logger . error ( 'Task "' + taskName + '" failed.' ) ; throw new Error ( 'Task "' + taskName + '" failed.' ) ; } await this . driverHelper . wait ( TestConstants . TS_SELENIUM_DEFAULT_POLLING * 5 ) ; return false ; } , timeout , 'Timed out waiting for task ' + taskName + ' to succeed.' ) ; } private getTerminalTabCssLocator ( tabTitle ) { return `li[title='${ tabTitle }']` ; } private getFocusedTerminalTabLocator ( tabTitle ) { return By . css ( `li[title='${ tabTitle }'].p-mod-current.theia-mod-active` ) ; } private async getTerminalID ( terminalTitle ) { const terminalTabXpathLocator = `//div[@id='theia-bottom-content-panel']//li[contains(@title, '${ terminalTitle }')]` ; const terminalTabs = await this . driverHelper . waitAllPresence ( By . xpath ( terminalTabXpathLocator ) ) ; if ( terminalTabs . length > 1 ) { throw new error . InvalidSelectorError ( `Terminal.getTerminalID Selector is too generic, found more than one terminal with title:${ terminalTitle }` ) ; } if ( terminalTabs . length === 1 ) { return await ( await terminalTabs [ 0 ] . getAttribute ( 'id' ) ) . replace ( 'shell-tab-' , '' ) ; } throw new error . NoSuchElementError ( `The terminal with title '${ terminalTitle }' has not been found.` ) ; } private getTerminalEditorInteractionEditorLocator ( terminalID ) { return By . xpath ( `//div[@id='${ terminalID }']//textarea[@aria-label='Terminal input']` ) ; } private getTerminalEditorTerminalRowsLocator ( terminalID ) { return By . xpath ( `//div[@id='${ terminalID }']//div[@class='xterm-rows xterm-focus']` ) ; } }