-
Notifications
You must be signed in to change notification settings - Fork 117
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
Make WebDriver available from HTML Elements #56
Comments
You can access the underlying WebElement via
Are you sure you can't act directly on the element, like |
@aik099 I know about
No, there's no such capability. Besides, we might need more complex actions there that we'll have to build using Actions builder. Besides, Apache 2.0 allows to modify sources and use them in non-Apache project, right? so that we can fork HTML Elements and implement this ourselves, in case there's no positive output from the devs? |
Better not to go that road. I suggest you sending a PR with proposed functionality. I personally don't think that exposing driver used to build up the TypifiedElement will harm anybody or doesn't conform to library's idea. So 👍 |
@Actine feel free to send you PR implementing this issue, didn't see any problems here |
Hi, guys. I need this feature too. |
@paulakimenko the truth is, I implemented this in my project long ago. It required implementing own decorators and a list proxy, which ended up with a lot of copy-paste from the library's code (because of #68). I'm just too lazy to make pull requests, mostly because it requires additional effort (supplying unit tests). |
@Actine , sorry, could you send example if you have it? |
@paulakimenko here's the idea
public interface WebDriverAware {
public void setWebDriver(WebDriver driver);
} public class MyPageComponent extends HtmlElement implements WebDriverAware {
private WebDriver driver;
public void setWebDriver(WebDriver driver) { this.driver = driver; }
...
public void doubleClick() {
new Actions(this.driver).doubleClick(this.label).perform();
}
}
public class MyFactory {
private WebDriver driver;
public MyFactory(WebDriver driver) { this.driver = driver; }
...
public <T extends WebElement> T initPage(Class<T> objectClass) {
try {
T object = objectClass.newInstance();
WebDriverAwareDecorator decorator = new WebDriverAwareDecorator(driver);
decorator.setWebDriver(driver);
PageFactory.initElements(decorator, object);
return object;
} catch (InstantiationException e) {
// Use some custom exception rather than generic RuntimeException
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
} // somewhere around starting a new session
MyFactory myFactory = new MyFactory(driver);
// somewhere in test
MyPage page = myFactory.initPage(MyPage.class);
page.getMyComponent().doubleClick(); // should use the recursively injected driver Hope this helps. Adjust to your architecture. Please reply whether you got it working (I trimmed down irrelevant stuff that we have in our implementation, might not compile at first 😃 ) |
@Actine thank you. It works fine) |
I need to use WebDriverWait in my html element but am unable to do this currently because the constructor requires a WebDriver object. Is there any chance you can implement this functionality? I'm using 'ru.yandex.qatools.htmlelements:htmlelements-java:1.15' |
@andrew-sumner can you describe problem you solving please? |
I have a responsive web application with two different navigation menu's: one for phone layout and one for desktop layout. I'm using the HtmlElement as a wrapper for the navigation menu but I need to put a wait command in to ensure that one or the other menu has finished loading and is visible before attempting to access the WebElement and would prefer to use a WebDriverWait command which requires access to the underlying WebDriver. |
Why not use |
And even without |
I hadn't seen the @timeout annotation before, but found it buried in the release notes. It may meet this requirement, I'll have to look into the implementation a bit more first. Recommended advice is not to mix explicit and implicit waits (http://www.seleniumhq.org/docs/04_webdriver_advanced.jsp), we perform explicit waits using WebDriverWait when needed. What does the @timeout annotation do behind the scenes? My second scenario (not previously mentioned) is that sometimes I'd like to call the findElement() method on the driver so that I can use a more customised selector. Eg in a calendar control I'd like to wrap in an HtmlElement I currently use driver.findElement(By.cssSelector("li[data-date='" + date + "']")); to return the element for a specific date. In the same way that the original poster did not want to pass the driver into the method so that he can call an action, I don't want to pass in the driver just to call findElement when the HtmlElement presumably already knows what driver is being used. |
it's an element-specific implicit wait
I'll not recommend to do any direct driver calls since you introduce PageObject architecture in your project. In your specific case you can describe calendar items as collection and then iterate to find one with required date. Using lamdaj library and matchers will help a lot here. |
I certainly understand that you want to keep to a pure page object pattern, unfortunately for me that comes at the cost of some flexibility in how I can use your very awesome project. How would you suggest I do this one then? (I just encountered this issue today) The below class is a block element that represents a menu. The web pages its used in contain iframes, although this menu it not in a frame. I don't want to have to worry about the iframes for the menu item in any of my pages, and I don't want to have to pass the driver into the component as in my example below. In my page object I'd like to declare the component as a class variable and have the page factory instantiate it:
And use it like this (the navigate using method places a red border around the element and takes a screen shot for documentation/debugging):
My class
|
So the main problem is transparent switching between frames the elements are located in, when those elements are accessed. I also have exact same problem in my PHP version of this library: qa-tools/qa-tools#116 The problem, in my case, if that reference to an element (that might itself be in a frame) isn't kept, when element is found. Although it might be really cool to allow referencing frames in xpath of the element. |
Yep, handling iframes is a completely different (and pretty complex) story. Implementing it as element annotation will require checking current frame for every element call, which will slow down test execution unpredictably. @andrew-sumner in your specific case i would implement |
Original poster here. I'm not doing Selenium automation for a year already, but seeing the issue being brought up again I decided to jump into the discussion. @artkoshelev sorry but it seems that you're trying to avoid implementing the requested feature at all cost :) suggesting suboptimal workarounds and new annotations only to not expose the driver. However, as far as I understand, the use case in my original message (building Actions such as double-click or context click on an element) is still not addressed. @andrew-sumner In your case with a date picker you don't necessarily need a driver to find an element with customized selector. Any Also there's still my solution from the comment above. Now that #68 is addressed, you don't have to copy-paste those two classes but extend and override a few methods. |
Need for webdriver instance inside elements is a smell of bad test architecture for me. WebElements and HtmlElements were created to describe page structure, not actions. To implement actions which need webdriver just use objects which already knows about webdriver - pages or steps (see http://www.thucydides.info/#/ or http://allure.qatools.ru/). |
@artkoshelev then why WebElements/HtmlElements have methods like I agree that the use of WebDriver instance in page objects / components must be put to the minimum if not avoided completely. But sometimes it's justified. |
@artkoshelev I'm not convinced that I would use an @iFrame annotation, i'd prefer to handle that myself. You state "which will handle frame switching before and after method execution", I might want that behaviour in some cases, in other's (like my example above) I don't want the frame to switch back after execution. Same applies to the @time annotation as well - I'm not sure that I'm ever likely to use it as we have a policy against using implicit waits and only use explicit waits as required. If you won't supply the webdriver I guess I will either continue to pass in the webdriver as required or look at the solution @Actine mentioned. I disagree with your above statement that "need for webdriver instance inside elements is a smell of bad test architecture". In some cases it's the only way to interact with some complex web elements, for example: have you ever tried automating a Dojo based web application? |
@Actine Thanks for the suggestion - I've implement it and it was so easy given the changes in the latest version of htmlelements. Here's my implementation for anyone else that may have this problem: @artkoshelev While I believe this functionality should be part of the project, I'm very impressed with how easy it was to extend htmlelements to meet my requirement - so a big thanks to everyone who have worked to develop this tool. Create these classes
Construct page object
Example Implementation
|
@andrew-sumner so, how about proposing PR with your feature implementation? =) |
PR created :-) |
PR now passes sonar checks... |
СС @tmatveyeva |
Hello Yandex,
We are developing a test framework for our rich web application using Java, Selenium, Spring for dependency management, and HTML Elements for defining layouts. We employ a strict separation of concerns where Pages, Elements, and nested Elements not only declare the composition, but methods to interact with them (somewhat similar to Views in Backbone.Marionette MVC). This way they provide an API to the higher level but never expose the elements themselves.
In these methods we sometimes need to have a current WebDriver instance (e.g. to perform double-click or other non-standard Actions), that is, the same WebDriver that was used by Page Object Factory to initialize the elements. Currently the HTML Element entities (Buttons, Links etc) are not aware of WebDriver that initialized them, so we have to pass its instance to those methods explicitly, which is not a very nice workaround:
Could you please consider to make WebDriver available, so that we could get it in a fashion like this:?
Thank you in advance,
With best regards,
~Actine
The text was updated successfully, but these errors were encountered: