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

[TS-SELENIUM] Cover the "Start a Workspace from a devfile" step from "Happy path" scenario #13479

Merged
merged 4 commits into from
Jun 7, 2019

Conversation

Ohrimenko1988
Copy link
Contributor

What does this PR do?

Cover the "Start a Workspace from a devfile" step from "Happy path" scenario

What issues does this PR fix or reference?

Issue: #13356

Release Notes

Docs PR

@Ohrimenko1988 Ohrimenko1988 added kind/task Internal things, technical debt, and to-do tasks to be performed. team/che-qe labels Jun 5, 2019
@@ -13,44 +13,74 @@ import { DriverHelper } from '../../utils/DriverHelper';
import { CLASSES } from '../../inversify.types';
import { TestConstants } from '../../TestConstants';
import { By, Key } from 'selenium-webdriver';
import { error } from 'selenium-webdriver';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be appended to the upper row as import { By, Key, error } from 'selenium-webdriver';

await this.driverHelper.waitVisibility(By.css(Editor.SUGGESTION_WIDGET_BODY_CSS), timeout);
}

async waitSuggestionContainerClosed(attempts: number = TestConstants.TS_SELENIUM_DEFAULT_ATTEMPTS, polling: number = TestConstants.TS_SELENIUM_DEFAULT_POLLING) {
await this.driverHelper.waitDisappearance(By.css(Editor.SUGGESTION_WIDGET_BODY_CSS), attempts, polling);
public async waitSuggestionContainerClosed(attempts: number = TestConstants.TS_SELENIUM_DEFAULT_ATTEMPTS,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest to remove parameters ' attempts ' and ' polling ' as they are not used.


await this.pressEscapeButton(editorTabTitle);
await this.waitSuggestionContainerClosed();
await this.pressControlSpaceCombination(editorTabTitle);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NOTE 1: If I understand correctly reason of this is - if the suggestion is not shown, test tries to view it by pressing ctrl + space. Shouldn't there be another check if the suggestion is shown correctly for that second attempt?

NOTE 2: Why does pressing ctrl + space have own method? Why not to call performKeyCombination directly from here?

Copy link
Contributor Author

@Ohrimenko1988 Ohrimenko1988 Jun 5, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Answer 1: Not exactly. Described logic encapsulated in the "wait" method, this is a kind of loop, it will repeat until called method returns some value, or timeout end.

await this.waitSuggestionContainer();
            try {
                await this.driverHelper.waitVisibility(suggestionLocator, 5000);
                return true;
            } catch (err) {
                const isTimeoutError: boolean = err instanceof error.TimeoutError;
                if (!isTimeoutError) {
                    throw err;
                }

                await this.pressEscapeButton(editorTabTitle);
                await this.waitSuggestionContainerClosed();
                await this.pressControlSpaceCombination(editorTabTitle);
            }

Answer 2: It looks much better for me to use particular method for invoking suggestion container than repeat each time this.performKeyCombination(editorTabTitle, Key.chord(Key.CONTROL, Key.SPACE))

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Answer 2: You still need to write a line of code - even performKeyCombination or pressControlSpaceCombination. It is quite weird to have methods that contain only one line this way. And it doesn't seem to be frequent method - only 2 usages. The escapeButton is called only once.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I must say, that I'm not really fond of this approach either. Maybe if these "typical" key combinations would live in separate classes, then it would be ok. But having such methods in Editor class is not very nice IMO.
But I don't want to block this PR because of this.

throw err;
}

await this.pressEscapeButton(editorTabTitle);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not to call performKeyCombination directly from here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Answer 2 #13479 (comment)

@Ohrimenko1988 Ohrimenko1988 removed the request for review from musienko-maxim June 5, 2019 12:27
@Ohrimenko1988
Copy link
Contributor Author

ci-build

…cenario

Signed-off-by: Ihor Okhrimenko <iokhrime@redhat.com>
@Ohrimenko1988
Copy link
Contributor Author

ci-build

Copy link
Contributor

@rhopp rhopp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've put some comments to this PR.
We've also had meeting to discuss more possible changes, but those will be done in separate PR.

e2e/README.md Show resolved Hide resolved
});
}
});
const isReportDirExist: boolean = fs.existsSync(reportDirPath);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reportDirExists would be better name IMO.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am guided by "Java" code conduct which pointed that "is" prefix should be used for boolean variables and methods. Is it the right convention for "Typescript"?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not aware of such convention... Even in java it's usual to have different prefixes like has<Property>, should<beAbleToDoSomething>, ... Basically anything meaningfull is better, than something not making sense (in this case two verbs in one "sentence"(var name))
Anyway... looking at this code I don't see this variable used anywhere else, so maybe put the fs.existsSync() directly into the condition?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On my opinion this is

      const reportDirExists: boolean = fs.existsSync(reportDirPath);

      if (!reportDirExists) {
        fs.mkdirSync(reportDirPath);
      }

more clear then

      if (!fs.existsSync(reportDirPath)) {
        fs.mkdirSync(reportDirPath);
      }

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's agree to disagree on the approach :-D What about the name?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Already changed =)

}

// create dir for failed test report if not exist
const isTestReportDirExist: boolean = fs.existsSync(testReportDirPath);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

testReportDirExists would be better name IMO.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can see this pattern in more places in this PR, so I won't comment it any further, but the objection still holds ;-)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}

async waitSuggestion(suggestionText: string, timeout: number = TestConstants.TS_SELENIUM_DEFAULT_TIMEOUT) {
await this.driverHelper.waitVisibility(By.xpath(this.getSuggestionLineXpathLocator(suggestionText)), timeout);
public async waitSuggestion(editorTabTitle: string,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I understand this correctly, all the methods here are now requiring editor tab title (a.k.a. name of the file opened in this editor?).
Wouldn't it be better to pass that in the constructor? This way we could have multiple instances of editor - the same way, as user can have multiple editors opened.
Doing that we could go even further - having method editor.setFocus() to set focus to this editor. And maybe even further? Calling the setFocus() every time, when we try to operate with this editor (for example by editor.type()) to make sure the correct editor is in focus?

Copy link
Contributor Author

@Ohrimenko1988 Ohrimenko1988 Jun 6, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added to issue: #13479 (comment)


return elementText.search(expectedText) > 0;
if (isTextPresent) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't simple return isTextPresent be nicer? ;-)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not exactly.
Method "wait" waits until some value is returned,
if we return "false" method will pass,
so that's why we need this "if" check and return
value just in case of successful check

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For a {@link webdriver.Condition} or function, the wait will repeatedly evaluate the condition until it returns a truthy value. 

From this it seems to me, that returning false should cause the wait loop to be executed again...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can check it yourself, it works as I described

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hehe... Unfortunately I dont have time to try now, so I believe you :-D


}, timeout);
if (isTextAbsent) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as with isTextPresent

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}, timeout);
}

async waitSuccessBuildText(editorTabTitle: string,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Such specific method shouldn't be here... Instead we should have something like waitForText(editor, text, timeout, polling)

await this.driverHelper.waitDisappearance(By.css('div.theia-mini-browser'));
}

async waitSpringAvailable(timeout: number = TestConstants.TS_SELENIUM_DEFAULT_TIMEOUT,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Too specific method for page object... Instead of this we should take By(?) locator, which we should look for inside the preview page object?

return true;
}

await this.driverHelper.getDriver().switchTo().defaultContent();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This section seems weird to me... Is it some workaround for some problem?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

part of the preview widget placed in the iframe

@Ohrimenko1988
Copy link
Contributor Author

I have created an issue with described required improvements
#13486

Signed-off-by: Ihor Okhrimenko <iokhrime@redhat.com>
Signed-off-by: Ihor Okhrimenko <iokhrime@redhat.com>
}, timeout);
}

async waitForText(editorTabTitle: string,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm... now, the method is called "generally", but it's still waiting for some specific, hard-coded text.
My original suggestion was to rewrite the method to take string parameter (text to wait for).

Now I can also see we already have such method (waitText), but that one has slightly different logic (it's not scrolling down, as this one).
Maybe this one shoud be renamed&rewritten to something like

followAndWaitForText(editorTabTitle: string, textToSearchFor: string, timeout: number, polling:number)

Signed-off-by: Ihor Okhrimenko <iokhrime@redhat.com>
@Ohrimenko1988 Ohrimenko1988 merged commit 8af9570 into master Jun 7, 2019
@Ohrimenko1988 Ohrimenko1988 deleted the selen-happy-path branch June 7, 2019 15:49
@che-bot che-bot added this to the 7.0.0 milestone Jun 27, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/task Internal things, technical debt, and to-do tasks to be performed.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants