From dadb74bc9fd4f6f6abf8122c7fa42439a9a6fe10 Mon Sep 17 00:00:00 2001 From: musienko maksym Date: Thu, 19 Sep 2019 09:00:21 +0300 Subject: [PATCH] implement workaround for Go to symbol feature Signed-off-by: musienko maksym --- e2e/driver/ChromeDriver.ts | 4 +-- e2e/driver/ContainerInitializer.ts | 2 ++ e2e/index.ts | 29 ++++++++-------- e2e/inversify.types.ts | 3 +- e2e/pageobjects/ide/ContextMenu.ts | 39 ++++++++++++++++++++++ e2e/pageobjects/ide/Editor.ts | 39 ++++++++++++++++++++-- e2e/pageobjects/ide/ProjectTree.ts | 4 +-- e2e/tests/e2e_happy_path/HappyPath.spec.ts | 21 ++++++++---- e2e/utils/DriverHelper.ts | 8 ++++- 9 files changed, 120 insertions(+), 29 deletions(-) create mode 100644 e2e/pageobjects/ide/ContextMenu.ts diff --git a/e2e/driver/ChromeDriver.ts b/e2e/driver/ChromeDriver.ts index 95f4d2ea25b..c2e95bdfebd 100644 --- a/e2e/driver/ChromeDriver.ts +++ b/e2e/driver/ChromeDriver.ts @@ -38,7 +38,6 @@ export class ChromeDriver implements IDriver { .addArguments('--no-sandbox') .addArguments('--disable-web-security') .addArguments('--allow-running-insecure-content'); - // if 'true' run in 'headless' mode if (TestConstants.TS_SELENIUM_HEADLESS) { options = options.addArguments('headless'); @@ -52,11 +51,10 @@ export class ChromeDriver implements IDriver { .forBrowser('chrome') .setChromeOptions(options); - // if 'true' run with remote driver + // if 'true' run with remote driver if (TestConstants.TS_SELENIUM_REMOTE_DRIVER_URL) { builder = builder.usingServer(TestConstants.TS_SELENIUM_REMOTE_DRIVER_URL); } - return builder; } diff --git a/e2e/driver/ContainerInitializer.ts b/e2e/driver/ContainerInitializer.ts index 6cb5874a9e9..0f69e3ea600 100644 --- a/e2e/driver/ContainerInitializer.ts +++ b/e2e/driver/ContainerInitializer.ts @@ -39,6 +39,7 @@ import { OcpLoginPage } from '../pageobjects/openshift/OcpLoginPage'; import { OcpWebConsolePage } from '../pageobjects/openshift/OcpWebConsolePage'; import { OcpLoginByTempAdmin } from '../pageobjects/login/OcpLoginByTempAdmin'; import { OpenWorkspaceWidget } from '../pageobjects/ide/OpenWorkspaceWidget'; +import { ContextMenu } from '../pageobjects/ide/ContextMenu'; import { ITestWorkspaceUtil } from '..'; export function getContainer(): Container { @@ -54,6 +55,7 @@ export function getContainer(): Container { e2eContainer.bind(TYPES.CheLogin).to(SingleUserLoginPage).inSingletonScope(); } + e2eContainer.bind(CLASSES.ContextMenu).to(ContextMenu).inSingletonScope(); e2eContainer.bind(CLASSES.DriverHelper).to(DriverHelper).inSingletonScope(); e2eContainer.bind(CLASSES.Dashboard).to(Dashboard).inSingletonScope(); e2eContainer.bind(CLASSES.Workspaces).to(Workspaces).inSingletonScope(); diff --git a/e2e/index.ts b/e2e/index.ts index 91cb72bd752..5fdd32c0160 100644 --- a/e2e/index.ts +++ b/e2e/index.ts @@ -3,36 +3,37 @@ export { inversifyConfig }; export * from './inversify.types'; export * from './TestConstants'; -export * from './driver/ChromeDriver'; -export * from './driver/IDriver'; export * from './driver/ContainerInitializer'; +export * from './driver/IDriver'; +export * from './driver/ChromeDriver'; export * from './utils/ScreenCatcher'; export * from './utils/DriverHelper'; export * from './utils/NameGenerator'; export * from './utils/workspace/ITestWorkspaceUtil'; export * from './utils/workspace/WorkspaceStatus'; export * from './utils/workspace/TestWorkspaceUtil'; +export * from './pageobjects/openshift/OcpLoginPage'; +export * from './pageobjects/openshift/OcpWebConsolePage'; export * from './pageobjects/login/OcpLoginByTempAdmin'; +export * from './pageobjects/login/ICheLoginPage'; export * from './pageobjects/login/MultiUserLoginPage'; export * from './pageobjects/login/IOcpLoginPage'; -export * from './pageobjects/login/ICheLoginPage'; export * from './pageobjects/login/SingleUserLoginPage'; -export * from './pageobjects/dashboard/NewWorkspace'; -export * from './pageobjects/dashboard/Workspaces'; export * from './pageobjects/dashboard/workspace-details/WorkspaceDetails'; export * from './pageobjects/dashboard/workspace-details/WorkspaceDetailsPlugins'; +export * from './pageobjects/dashboard/Workspaces'; export * from './pageobjects/dashboard/Dashboard'; +export * from './pageobjects/dashboard/NewWorkspace'; export * from './pageobjects/ide/Terminal'; -export * from './pageobjects/ide/TopMenu'; -export * from './pageobjects/ide/RightToolbar'; -export * from './pageobjects/ide/OpenWorkspaceWidget'; -export * from './pageobjects/ide/Ide'; export * from './pageobjects/ide/Editor'; +export * from './pageobjects/ide/OpenWorkspaceWidget'; export * from './pageobjects/ide/ProjectTree'; -export * from './pageobjects/ide/PreviewWidget'; -export * from './pageobjects/ide/GitHubPlugin'; +export * from './pageobjects/ide/QuickOpenContainer'; +export * from './pageobjects/ide/RightToolbar'; +export * from './pageobjects/ide/ContextMenu'; +export * from './pageobjects/ide/Ide'; export * from './pageobjects/ide/DebugView'; +export * from './pageobjects/ide/GitHubPlugin'; +export * from './pageobjects/ide/TopMenu'; export * from './pageobjects/ide/WarningDialog'; -export * from './pageobjects/ide/QuickOpenContainer'; -export * from './pageobjects/openshift/OcpWebConsolePage'; -export * from './pageobjects/openshift/OcpLoginPage'; +export * from './pageobjects/ide/PreviewWidget'; diff --git a/e2e/inversify.types.ts b/e2e/inversify.types.ts index b3b8e9911b6..da77c757c36 100644 --- a/e2e/inversify.types.ts +++ b/e2e/inversify.types.ts @@ -37,7 +37,8 @@ const CLASSES = { ScreenCatcher: 'ScreenCatcher', OcpLoginPage: 'OcpLoginPage', OcpWebConsolePage: 'OcpWebConsolePage', - OpenWorkspaceWidget: 'OpenWorkspaceWidget' + OpenWorkspaceWidget: 'OpenWorkspaceWidget', + ContextMenu: 'ContextMenu' }; export { TYPES, CLASSES }; diff --git a/e2e/pageobjects/ide/ContextMenu.ts b/e2e/pageobjects/ide/ContextMenu.ts new file mode 100644 index 00000000000..4cb23a04387 --- /dev/null +++ b/e2e/pageobjects/ide/ContextMenu.ts @@ -0,0 +1,39 @@ +import 'reflect-metadata'; +import { injectable, inject } from 'inversify'; +import { DriverHelper } from '../../utils/DriverHelper'; +import { CLASSES } from '../../inversify.types'; +import { WebElement, Button, By, Key} from 'selenium-webdriver'; +import { TestConstants} from '../../TestConstants'; + + + +@injectable() +export class ContextMenu { + private static readonly SUGGESTION_WIDGET_BODY_CSS: string = 'ul.p-Menu-content'; + + constructor(@inject(CLASSES.DriverHelper) private readonly driverHelper: DriverHelper) { } + + + async invokeContextMenuOnTheElementWithMouse(elementLocator: By, timeout: number = TestConstants.TS_SELENIUM_DEFAULT_TIMEOUT ) { + const webElement: WebElement = await this.driverHelper.waitVisibility(elementLocator, timeout); + await this.driverHelper.getAction().click(webElement, Button.RIGHT).perform(); + this.waitContextMenu(timeout); + } + async invokeContextMenuOnActiveElementWithKeys( timeout: number = TestConstants.TS_SELENIUM_DEFAULT_TIMEOUT ) { + this.driverHelper.getDriver().switchTo().activeElement().sendKeys(Key.SHIFT + Key.F10); + this.waitContextMenu(timeout); + } + + + async waitContextMenuAndClickOnItem(nameOfitem: string, timeout: number = TestConstants.TS_SELENIUM_DEFAULT_TIMEOUT ) { + const itemLocator: string = `//div[@class='p-Menu-itemLabel' and text()='${nameOfitem}']`; + await this.waitContextMenu(); + await this.driverHelper.waitAndClick(By.xpath(itemLocator), timeout); + } + + async waitContextMenu(timeout: number = TestConstants.TS_SELENIUM_DEFAULT_TIMEOUT) { + await this.driverHelper.waitVisibility(By.css(ContextMenu.SUGGESTION_WIDGET_BODY_CSS), timeout); + } + + +} diff --git a/e2e/pageobjects/ide/Editor.ts b/e2e/pageobjects/ide/Editor.ts index 23d34ea5e41..d3c2bf829b7 100644 --- a/e2e/pageobjects/ide/Editor.ts +++ b/e2e/pageobjects/ide/Editor.ts @@ -12,9 +12,10 @@ import { injectable, inject } from 'inversify'; import { DriverHelper } from '../../utils/DriverHelper'; import { CLASSES } from '../../inversify.types'; import { TestConstants } from '../../TestConstants'; -import { By, Key, error } from 'selenium-webdriver'; +import { By, Key, error, ActionSequence, Button } from 'selenium-webdriver'; import { Ide } from './Ide'; + @injectable() export class Editor { private static readonly SUGGESTION_WIDGET_BODY_CSS: string = 'div.visible[widgetId=\'editor.widget.suggestWidget\']'; @@ -278,7 +279,8 @@ export class Editor { } } - private async getLineYCoordinates(lineNumber: number): Promise { + + async getLineYCoordinates(lineNumber: number): Promise { const lineNumberLocator: By = By.xpath(`//div[contains(@class, 'line-numbers') and text()='${lineNumber}']` + `//parent::div[contains(@style, 'position')]`); @@ -296,6 +298,39 @@ export class Editor { return lineYCoordinate; } + async clickOnTheTextInDefinedPosition(line: number, column: number) { + const addishionalShifting = 19; + const addishionalShiftingToX = 1; + const yPosition: number = await this.getLineYCoordinates(line) + addishionalShifting; + const xPosition: number = column + addishionalShiftingToX; + new ActionSequence(this.driverHelper.getDriver()). + mouseMove({x: xPosition, y: yPosition}). + click(). + perform(); +} + + async goToDefinitionWithMouseClicking(line: number, column: number) { + const addishionalShiftingToY = 19; + const addishionalShiftingToX = 1; + const yPosition: number = await this.getLineYCoordinates(line) + addishionalShiftingToY; + new ActionSequence(this.driverHelper.getDriver()). + keyDown(Key.CONTROL). + mouseMove({x: column + addishionalShiftingToX, y: yPosition}). + click(). + keyDown(Key.CONTROL). + perform(); + } + + async mouseContextClickInDefinedPosition(line: number, column: number) { + const addishionalShiftingToY = 19; + const addishionalShiftingToX = 1; + const yPosition: number = await this.getLineYCoordinates(line) + addishionalShiftingToY; + new ActionSequence(this.driverHelper.getDriver()). + mouseMove({x: column + addishionalShiftingToX, y: yPosition}). + click(Button.RIGHT). + perform(); + } + private getTabWithUnsavedStatus(tabTitle: string): By { return By.xpath(`//div[text()='${tabTitle}']/parent::li[contains(@class, 'theia-mod-dirty')]`); } diff --git a/e2e/pageobjects/ide/ProjectTree.ts b/e2e/pageobjects/ide/ProjectTree.ts index 0dadf1fdfd5..d01fe021cf7 100644 --- a/e2e/pageobjects/ide/ProjectTree.ts +++ b/e2e/pageobjects/ide/ProjectTree.ts @@ -131,13 +131,13 @@ export class ProjectTree { } async expandPathAndOpenFile(pathToItem: string, fileName: string, timeout: number = TestConstants.TS_SELENIUM_DEFAULT_TIMEOUT) { - let items:Array = pathToItem.split('/'); + let items: Array = pathToItem.split('/'); let projectName: string = items[0]; let paths: Array = new Array(); paths.push(projectName); // make direct path for each project tree item - for(let i = 1; i < items.length; i++){ + for (let i = 1; i < items.length; i++) { let item = items[i]; projectName = `${projectName}/${item}`; paths.push(projectName); diff --git a/e2e/tests/e2e_happy_path/HappyPath.spec.ts b/e2e/tests/e2e_happy_path/HappyPath.spec.ts index ca4445c3205..f09bf2a586b 100644 --- a/e2e/tests/e2e_happy_path/HappyPath.spec.ts +++ b/e2e/tests/e2e_happy_path/HappyPath.spec.ts @@ -9,7 +9,7 @@ **********************************************************************/ import { e2eContainer } from '../../inversify.config'; -import { DriverHelper } from '../../utils/DriverHelper'; +import { DriverHelper, } from '../../utils/DriverHelper'; import { TYPES, CLASSES } from '../../inversify.types'; import { Ide, RightToolbarButton } from '../../pageobjects/ide/Ide'; import { ProjectTree } from '../../pageobjects/ide/ProjectTree'; @@ -26,6 +26,7 @@ import { Terminal } from '../../pageobjects/ide/Terminal'; import { OpenWorkspaceWidget } from '../../pageobjects/ide/OpenWorkspaceWidget'; import { ICheLoginPage } from '../../pageobjects/login/ICheLoginPage'; import * as fs from 'fs'; +import { ContextMenu } from '../../pageobjects/ide/ContextMenu'; const driverHelper: DriverHelper = e2eContainer.get(CLASSES.DriverHelper); const ide: Ide = e2eContainer.get(CLASSES.Ide); @@ -33,6 +34,7 @@ const projectTree: ProjectTree = e2eContainer.get(CLASSES.ProjectTree); const topMenu: TopMenu = e2eContainer.get(CLASSES.TopMenu); const quickOpenContainer: QuickOpenContainer = e2eContainer.get(CLASSES.QuickOpenContainer); const editor: Editor = e2eContainer.get(CLASSES.Editor); +const contextMenu: ContextMenu = e2eContainer.get(CLASSES.ContextMenu); const previewWidget: PreviewWidget = e2eContainer.get(CLASSES.PreviewWidget); const rightToolbar: RightToolbar = e2eContainer.get(CLASSES.RightToolbar); const terminal: Terminal = e2eContainer.get(CLASSES.Terminal); @@ -116,10 +118,11 @@ suite('Language server validation', async () => { await editor.waitSuggestion(javaFileName, 'run(Class primarySource, String... args) : ConfigurableApplicationContext'); }); - // it's skipped because of issue https://github.com/eclipse/che/issues/14520 - test.skip('Codenavigation', async () => { + + test('Codenavigation', async () => { await editor.moveCursorToLineAndChar(javaFileName, 32, 17); - await editor.performKeyCombination(javaFileName, Key.chord(Key.CONTROL, Key.F12)); + await checkCodeNavigationWithContextMenu(); + // await editor.performKeyCombination(javaFileName, Key.chord(Key.CONTROL, Key.F12)); await editor.waitEditorAvailable(codeNavigationClassName); }); @@ -289,7 +292,12 @@ async function runTask(task: string) { await quickOpenContainer.clickOnContainerItem(task); await quickOpenContainer.clickOnContainerItem('Continue without scanning the task output'); } - +async function checkCodeNavigationWithContextMenu() { + await contextMenu.invokeContextMenuOnActiveElementWithKeys(); + await contextMenu.waitContextMenuAndClickOnItem('Go to Definition'); + console.log('please check the satus of the known issue: https://github.com/eclipse/che/issues/14520. If it is fixed, we have to return the test to previous state.'); + return '' +} // sometimes under high loading the first click can be failed async function isureClickOnDebugMenu() { try { await topMenu.selectOption('Debug', 'Open Configurations'); } catch (e) { @@ -319,5 +327,6 @@ async function checkJavaPathCompletion() { await editor.type(classPathFilename, classpathText, 1); await editor.waitTabWithSavedStatus(classPathFilename); } -} + +} diff --git a/e2e/utils/DriverHelper.ts b/e2e/utils/DriverHelper.ts index c81c7760af6..967efc324cc 100644 --- a/e2e/utils/DriverHelper.ts +++ b/e2e/utils/DriverHelper.ts @@ -12,7 +12,7 @@ import { inject, injectable } from 'inversify'; import { TYPES } from '../inversify.types'; import { error, ActionSequence } from 'selenium-webdriver'; import 'reflect-metadata'; -import { ThenableWebDriver, By, until, WebElement } from 'selenium-webdriver'; +import { ThenableWebDriver, By, until, WebElement, Button } from 'selenium-webdriver'; import { TestConstants } from '../TestConstants'; @@ -258,6 +258,7 @@ export class DriverHelper { throw new error.TimeoutError(`Exceeded maximum gettin of the '${cssAttribute}' css attribute attempts, from the '${elementLocator}' element`); } + public async waitAttributeValue(elementLocator: By, attribute: string, expectedValue: string, @@ -445,10 +446,15 @@ export class DriverHelper { }, timeout); } + + async switchToSecondWindow(mainWindowHandle: string) { await this.waitOpenningSecondWindow(); const handles: string[] = await this.driver.getAllWindowHandles(); handles.splice(handles.indexOf(mainWindowHandle), 1); await this.driver.switchTo().window(handles[0]); } +async performRightClickOnActiveElement() { + await this.driver.actions().click(this.driver.switchTo().activeElement(), Button.RIGHT).perform(); +} }