Webdriver: expose selector/by/location of existing element - webdriver

The problem:
.Click()-ing a radio button webdriver element stales it(no control over the page that does this). The DOM element itself is still the same.
The goal:
I want to reset the existing webdriver element using its own original selector method so that it is no longer stale. I want a general solution that does not require knowing ahead of time how the element was found. I want to use the existing stale element to do the work. Ideal case would look something like this(using the following C# extension method just for sake of example):
IWebElement refreshedElement = driver.FindElement(staleElement.By());
The question:
Is there a way to expose the existing elements location? Is the 'address' of the element available anywhere? It doesn't even have to be the original method of addressing the element when it was found, I don't care about that. I'd just rather not have to make a subclass just to capture this information.

No, Selenium does not keep track of 'how' you found an element, and frankly I don't think that should be Selenium's responsibility.
I would wrap it into a new class, which inherits from RemoteWebElement, and has a method called RefindElement.

I might suggest considering adding the concept of a "Page Class". Basically, instead of adding the element to the test itself, I create a separate class that has methods that return elements.
For example, a login page would have three elements therefore 3 methods:
public class LoginPage
{
private IWebDriver driver { get; set; }
public CSCView_SalesAspx(IWebDriver driver) { this.driver = driver; }
public IWebElement Id { get { return driver.FindElement(By.Id("login_id")); } }
public IWebElement Pw { get { return driver.FindElement(By.Id("login_pw")); } }
public IWebElement SubmitBtn { get { return driver.FindElement(By.Id("submitBtn")); } }
}
Now all you have to do is instantiate the class then interact with the method. Your element should always be "fresh" since you're doing the lookup every time (without any extra work).
LoginPage loginPage = new LoginPage(driver);
loginPage.Id.SendKeys("myName");
loginPage.Pw.SendKeys("myPw");
loginPage.SubmitBtn.Click();
The best thing about this is if a page changes, instead of having to rewrite every test, you only change one page class and that fixes your broken tests.

Related

Selenium CSS selector :visible is not a valid selector

I'm using Page Objects to map elements in a page, something like that:
public class MyPage {
protected WebDriver driver;
#FindBy(css = "a[data-code=panel]:visible")
private WebElement cpaneladmin;
public MyPage(WebDriver driver) {
this.driver = driver;
PageFactory.initElements(this.driver, this);
}
}
The problem is this :visible CSS selector. Aparently, Selenium does not support it. Is there a way to select only visible elements using xpath or another kind of CSS selector?
Thanks
#FindBy(css = "a[data-code=panel]")
private List<WebElement> cpaneladmin;
Then iterate through the elements until you find the one that is displayed.
public WebElement FindDisplayed(WebElements elements)
{
foreach (WebElement element in elements)
{
if (element.isDisplayed()) // correct method: isDisplayed()
return element;
}
}
This should answer your question.
If you want to verify the element is visible another way, use element.IsDisplayed(), or use ExpectedConditions.
This might solve your problem,
List<WebElement> list = driver.findElements(By.cssSelector("selector_that_matches_one__or_more_elements"));
//do what ever you want with the elements in list
The above code will store all the visible elements that can be located by the provided selector.
Try using an implicit wait at the start of your code, for the above statements to be more effective.
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
When implicitly waiting, findElements() method will return as soon as there are more than 0 items in the found collection, or will return an empty list if the timeout(30 secs in the above case) is reached.
I came on this question a bit late, but here's how I resolved it in C#:
private void AssertAdminIsVisible(OpenQA.Selenium.IWebDriver wd)
{
OpenQA.Selenium.Support.UI.WebDriverWait wait = new OpenQA.Selenium.Support.UI.WebDriverWait(wd, TimeSpan.FromSeconds(60));
var cpaneladmin = wait.Until(SeleniumExtras.WaitHelpers.ExpectedConditions.ElementIsVisible(OpenQA.Selenium.By.CssSelector("a[data-code=panel]")));
Assert.IsNotNull(cpaneladmin);
}
And for.NET, it comes from the "DotNetSeleniumExtras.WaitHelpers" NuGet package:
you can also use :not([style*="display: none"]) as a workaround.

Rewiring actions of parent to a child viewmodel

So here's my screnario. I have a toolbar at the top (office style), with buttons. This is hosted in a shell. Some of those buttons are applicable only to certain child view models as they get loaded. Ideally what I would like to happen is have the buttons action.target repositioned to child view model as it gets created (I kind of got this working by settings Action.Target="ActiveItem" on them. This doesn't solve the problem fully though:
a) When the child viewmodel is closed and there is no active item, I want them to reposition to Shell as the target so they can be set to "default" state.
b) I noticed that when child viewmodel is closed and the shell being the conductor has it ActiveItem=null, the hooks from the action are still bound to the living instance of the last viewmodel, so doesn't looks like it got disposed of. Memory leak?
Any suggestions how to implement this scenario?
What about adding a property to your ShellViewModel which points to the action target and updating it when stuff gets activated/deactivated:
e.g.
public class ShellViewModel
{
public object ActionTarget
{
get { return _actionTarget; }
set
{
_actionTarget = value;
NotifyOfPropertyChange(() => ActionTarget);
}
}
// Then when the active item changes just update the target:
public override NotifyOfPropertyChange(string propertyName)
{
if(propertyName == "ActiveItem")
{
if(ActiveItem == null) ActionTarget = this;
else ActionTarget = ActiveItem;
}
}
}
Now bind to that:
<SomeMenu cal:Action.Target="{Binding ActionTarget}" />
Not sure if that will work or not but I'm sure I've done something similar in the past. (You may also have to explicitly call NPC on your actions before they will update after you have changed ActiveItem)

Adobe Flex3: Keyboard shortcuts when a view is visible?

I have a quite large Flex application with a large set of views and I ceratain views I'd like to add shortcuts.
And i'm looking for something like:
<mx:Vbox>
<foo:Shortcut keys="ctrl+s" action="{bar();}"/>
....
</mx:VBox>
Is there any framwork or component already done that does something like this? I guess it should be too difficult to build? When building this I only want the shortcuts to be active when the view is visible. How do I detect this? What base class is best to inherit from when working with non visual components?
I don't know of any framework component that does that already, but the examples above should get you started if you try to build your own.
There's no need to inherit from any component for a non-visual component like the one you've described here (your "foo" class needs no parents.) There's nothing in the Flex framework you need to inherit from for this.
However you architect it, your foo class is going to have to take in and parse keyboard codes to listen for and accept one or more methods to call. All you have to do is figure out when to add and remove the event listeners that will call the passed-in methods.
To handle turning your keyboard events on and off based on visibility, just have your foo component bind to the "visible" property of it's parent and add/remove event listeners accordingly.
You might also consider having the listeners added when the component that foo is nested in is on the display list rather than just visible. To do this, simply added and remove your event listeners in one of the component lifecycle methods - probably commitProperties is the most appropriate.
I don't think this solution answer your question directly but anyway, to help solve your problem here is an example.
For instance, I've extended the TextArea component like so. This is the best I can do so far, it can definitely be improved upon. Like, I don't know how to make the cursor go to the end after the next shortcut is pressed.
public class TextArea extends mx.controls.TextArea
{
// the keysmap is an example dictionary holding keycodes
private var keysmap:*={
112 = "some text for F1"
,113 = "the text for F2!"
//etc, etc
}
public var handleKeyDown:Boolean =false;
public function TextArea(){
if(handleKeyDown ==true){
this.addEventListener(KeyboardEvent.KEY_DOWN,this.keydownHandler);
}
}
public function keydownHandler(e:KeyboardEvent):void{
if(e.keyCode >= 112 && e.keyCode <= 123){
e.currentTarget["text"] += String(keysmap[e.keyCode]) +" ";
}//focusManager.setFocus(this);
}
}
I can't give you a solution using MXML, however my first thought would involve a singleton static class with a Dictionary that contains a list of objects as its keys and dynamically created dictionaries as the value pairing that contain keys denoting the desired key press with a function reference as the value.
So, say you had a Sprite and you wanted to capture ctrl+s for save when focus is on that object, I would get the instance of that Singleton, and call a function such as registerKeyBinding passing in the Sprite, the keyCode you want, and your pre-defined callback:
private var registeredObjects:Dictionary = new Dictionary(true);
public function registerKeyBinding(targetObject:Object, keyCode:int, callback:Function) {
if (registeredObjects[targetObject]) {
Dictionary(registeredObjects[targetObject])[keyCode] = callback;
}
else {
registeredObjects[targetObject] = new Dictionary();
Dictionary(registeredObjects[targetObject])[keyCode] = callback;
targetObject.addEventListener(KeyboardEvent.KEY_DOWN, keyDownListener);
}
}
private function keyDownListener(e:KeyboardEvent):void {
if (e.ctrlKey == true) {
//calls the function if that key exists.
Dictionary(registeredObjects[e.target])[e.keyCode];
}
}
Can't say I've tested this, but it was just the first thing that popped into my head. You could then setup functions to deregister and delete keys from the dictionaries, check states of the objects in addition to the keyCodes, remove old listeners, and delete entire dictionaries when there is no longer a need for them. Hopefully this is at least a tiny bit helpful.

Handling complex navigation in Flex

I am building a complex Flex app, and now I am at the point where navigation becomes a problem. I make use of Viewstacks with a Menu Bar, but I am not sure how to clearly structure this.
Depending on the logged in User and chosen Company by the user, he can see different pages. For now I restricted this hiding the appropriate buttons in the Menu Bar. However, not just the menu bar, but also buttons/links from within the app should be able to navigate to each existing page.
When I am loading up an existing page, it needs some initialization (depending on the context it is loaded from). In addition, when a company is chosen, I need to load the status from the backend, and depending on this status a specific page might be visible.
Are there any guidelines how to tackle more complex navigation/site hierarchies in Flex?
Now I am having all my views in a viewstack in the Application, and refer to it with Application.application.appViews.selectedChild -> but that's obviously not best practice, since it violates encapsulation.
Was thinking of implementing some sort of State Machine, which takes care of all this, but not quite sure it this would make sense, or if there is any better way.
Thanks guys,
Martin
If it's really complex, you might want to consider breaking your application up into modules.
Also, Mate is a great Flex framework for handling complex communication and navigation. Mate's EventMaps help you centralize the communication and logic between components, modules, etc. And, it keeps you away from the dreaded Application.application references.
Even if you don't use a framework like Mate, you can avoid the Application.application references by having components dispatch custom events that bubble up to the top-level of your application. The top level of the application can listen and catch these events and act on them. I've found this to be a much more flexible approach. I avoid Application.application as much as possible!
If you have a complex menu bar that needs to enable / disable a lot of buttons or options based on many different logic conditions, the State pattern is a decent way to handle it. I built an enterprise-level app that had a "Word-like" button bar at the top...and there were so many different conditions that affected the states of the buttons that I had to centralize the logic in one place. At first I didn't use the State pattern and maintaining the code was a difficult chore. One day, I bit the bullet and re-factored all the conditional logic into a StateManager class. It definitely made life easier from there on out.
Again, you might want to consider using Custom Events to broadcast important events to your application. You can make these events bubble up to the Application level. Then, by adding event listeners at the Application level, you can capture and respond to these events and target components or modules from the Application level. This gives you a central location for handling events and "directing traffic". It also prevents the tight-coupling of the Application.application approach. (Which quickly becomes a nightmare as your application grows and scales!)
For example, your StateManager can contain the case statements for deciding which state your application needs to be in. Once the decision about the current state is determined, you would dispatch a custom StateEvent. (Which might have properties like StateEvent.STATE_CHANGED and StateEvent.CURRRENT_STATE) This event can bubble up to the Application level and be caught by a listener. The listener then calls a method to load / change the state.
Does that clarify it for you? If not, perhaps I can spend an hour or two putting together a little sample.
Let me know,
=Bryan=
I can give you the approach I used for some of your sub-questions, the problem of initializing a page at runtime and how to encapsulate navigation.
For page initialization, the issue I came across is that it's not always known once you navigate to a page whether certain elements should be shown, since it not-only depends on overall user permissions, but also permissions against the currently-selected data. And if the information needed to determine this must be loaded from the server, you cannot show the page as-is while loading the information. So we created a control called LoadingPanel, which is a container that can cover content with a loading indicator until additional information has been received. Here's a shortened version of the ActionScript:
[DefaultProperty("children")]
public class LoadingPanel extends ViewStack
{
public function LoadingPanel()
{
this.resizeToContent = false;
super();
}
public function get children():Array { return _children }
public function set children(value:Array):void { _children = value; }
public function get loadingImageStyle():String {
return _loadingImgStyle; }
public function set loadingImageStyle(value:String):void {
_loadingImgStyle = value;
if (_loadingIndic)
_loadingIndic.loadingImageStyle = value;
}
public function showLoadingIndicator():void
{
if (_loadingIndic)
{
super.selectedChild = _loadingIndic;
}
else
{
_pendingLoadingIndic = true;
var me:LoadingPanel = this;
var listener:Function = function(event:Event):void
{
if (me._pendingLoadingIndic)
me.showLoadingIndicator();
}
addEventListener(FlexEvent.CREATION_COMPLETE, listener);
}
}
public function hideLoadingIndicator():void
{
_pendingLoadingIndic = false;
if (_content)
{
super.selectedChild = _content;
}
else
{
var me:LoadingPanel = this;
var listener:Function = function(event:Event):void
{
me.hideLoadingIndicator();
}
addEventListener(FlexEvent.CREATION_COMPLETE, listener);
}
}
public function waitForEvent(target:EventDispatcher, event:String):void
{
_eventCount++;
showLoadingIndicator();
var me:LoadingPanel = this;
target.addEventListener(
event,
function(evt:Event):void
{
me._eventCount--;
if (!me._eventCount)
{
me.hideLoadingIndicator();
}
}
);
}
override public function addChild(child:DisplayObject):DisplayObject
{
var result:DisplayObject = child;
if (_content)
{
result = _content.addChild(child);
invalidateDisplayList();
}
else
{
if (!_children)
{
_children = [];
}
_children.push(child);
}
return result;
}
override protected function createChildren():void
{
super.createChildren();
if (!_content)
{
_content = new Box();
_content.percentWidth = 1.0;
_content.percentHeight = 1.0;
super.addChild(_content);
}
if (!_loadingIndic)
{
_loadingIndic = new LoadingIndicator();
_loadingIndic.percentWidth = 1.0;
_loadingIndic.percentHeight = 1.0;
_loadingIndic.loadingImageStyle = _loadingImgStyle;
super.addChild(_loadingIndic);
}
if (_children)
{
for each (var child:DisplayObject in _children)
{
_content.addChild(child);
}
}
}
private var _loadingImgStyle:String = "loadingIndicatorDark";
private var _loadingIndic:LoadingIndicator = null;
private var _content:Box = null;
private var _children:Array = null;
private var _pendingLoadingIndic:Boolean = false;
private var _eventCount:int = 0;
}
We typically used these by wrapping a LoadingPanel around content then calling the panel's waitForEvent method. Typically, the event we'd wait for is for a web service response to come in. The class also lets you wait on multiple events before it will show its children.
Another recommendation I would make for your project is that you look into deep linking in Flex. Our users appreciated being able to bookmark a resource/location in our complex Flex application as well as being able to hit refresh in their browser and return to the same "page" they were on. But implementing deep linking also helped me out for one of the problems you mentioned; how do you send the UI to a specific page in an encapsulated manner? The way we did it is by raising a bubbling navigation event containing a destination "URL." A top-level navigation "manager" then handled interpreting the URL and "sending" the user to the appropriate area.
Hopefully this will give you some ideas for some of the challenges you face.

Flex: Special-casing an item in a list or menu?

I've found it's often useful to special case the first item in a drop-down menu (ie, an instance of Menu). For example, if I want to pick a color from the list provided by a web service:
<mx:PopUpMenuButton id="colorSelelector"
dataProvider="{colorsService.lastResult}" />
I might also want a special-case, which is "enter a new color", allowing the user to enter the RGB values for a new color which isn't in the list. For example:
var newColor = { label: "Enter a new color", rgb: null };
Then used with:
<mx:PopUpMenuButton id="colorSelelector"
dataProvider="{colorsService.lastResult}"
lastOption="{newColor}" />
So, apart from changing the list I get back from the service, is there any better way to do this?
(and just a preemptive comment: this is a simplification… I'm not actually trying to make a color-picking-list)
When you bind to the dataProvider, call a function that adds your special case. For instance:
<mx:PopUpMenuButton id="colorSelector"
dataProvider="{addSpecialCases(colorsService.lastResult)}"/>
So, apart from changing the list I get
back from the service, is there any
better way to do this?
This approach is going to be the cleanest, without extending HTTPService, which would work well (but is really just altering your result ;) ):
package
{
import mx.rpc.http.HTTPService;
public class MyHTTPService extends HTTPService
{
public var appendToResult:Object;
public function MyHTTPService(rootURL:String=null, destination:String=null)
{
super(rootURL, destination);
}
[Bindable("resultForBinding")]
override public function get lastResult():Object
{
//I know what my type is, Array as an example
var myResult:Array = operation.lastResult;
myResult.push( this.appendToResult )
return myResult;
}
}
}

Resources