Handle Javascript focus when using sendKeys in WebDriver - javascript

It's quite common for a web application to use Javascript to focus to a text field onload. For example, in a login page, we may use Javascript to focus to the username field.
When using WebDriver with FirefoxDriver, I use sendKeys to populate these fields. However, most of the time, the Javascript focus function will get executed while WebDriver is sending actual characters, so my input for another field (e.g. the password field) is partial and the remaining goes to the focused field.
How should I handle this case? To my knowledge, the blocking API returns when the page content is loaded, not when Javascript execution is finished, so this situation is understandable. However, I don't think using "Wait" is a decent solution, since it means too much intrusion to the test development.

I came up with three possible solutions, none of them is actually guaranteed to work:
Does javascript's document.readyState return "complete"? If not, you could wait for that after every click().
You could wait until driver.switchTo().activeElement(); (which returns the active element) returns your text field, and begin your typing afterwards. I guess you should call driver.switchTo().defaultContent(); afterwards, too, but am not sure about it. A similar approach would be getting document.activeElement.
Um, that's somewhat hacky, too. Write your own sendKeys method which finds the element, remembers it, and then sends one key from the wanted string at a time. Because WebDriver makes sure to have focus on the beginning of the typing, it should work.

Related

Is there a way to transform a page loaded by HtmlUnit before it starts executing javascript?

First I would like to describe the motivation for my question.
I have a complex web page to test with Selenium + HtmlUnit, which launches diverse javascript scripts. The problem which I describe should be quite common.
On the page there is a button to which jQuery binds a click callback (click event handler) after the page is loaded. There is an explicit Wait (this is a Selenium term) for the button to become clickable in the test code. So as soon as the button becomes clickable, it gets clicked by Selenium. Often, however, this happens before jQuery manages to attach to the button the click event handler. In this case the Selenium test fails.
What I thought to do is to preprocess the web page accessed by HtmlUnit before javascript starts executing on the page, injecting some <script>myownscript()</script>at the beginning of the page (so that it executes before any other script on that page). Then I would be able to know, controlling certain conditions in the Selenium test code, when exactly the attaching of the click event handler has happened (how I exactly do this, depends on the details of the application). If I make Selenium click the button then, the presence of the click event handler will be guaranteed, and the test would proceed further as planned - with no errors due to the missing click event handler.
Let us leave apart the question whether the idea is a good or a bad one (a much simpler one, of course, would be just introducing a large enough delay in the Selenium test code before trying to click the problematic button, but then there might be a problem with the overall duration of tests, because the problem I described is present on many pages of the application being tested).
Are there some hooks in Selenium/HtmlUnit which permit to preprocess the page fetched from the server, injecting a script as I described, before javascript starts executing on the page?
In this case, you can use JavaScriptExecutor. You can add a function to do anything you want in the String script.
WebElement button = driver.findElement(By.id("my-button"));
JavascriptExecutor jsExe = ((JavascriptExecutor) driver);
String script = "console.log(arguments[0].id); return arguments[0].id";
Object oj = jsExe.executeScript(script, button);
String txt = oj.toString();
System.out.println(txt);
Please be careful if you want to use aycn such as setTimeout(), it will return immediately. See an example for async method in my answer at: method execute_script don't wait end of script to return value with selenium in python

Capybara with js: true not finding checkbox

I need to test if Javascript alert is being displayed in validation proccess after checking one checkbox.
I'm using RSpec, Capybara with Webkit and Database Cleaner.
My test without JS: true :
it "alerts to choose two players" do
set_and_visit
first("input[type='checkbox']").set(true)
expect(page).to have_content('Remember that you must choose two players to start a game.')
end
Finds a checkbox but cannot find the alert message.
When I add JS - "alerts to choose two players", js: true do it returns an error
NoMethodError:
undefined method `set' for nil:NilClass
I've tried using check 'John Doe' and first("input[type='checkbox']").check but it still didn't work.
There are two possible issues that seem likely:
Asynchronous Issues
The default driver (rack-test) is synchronous, so the page will always be fully loaded by the time you run first. When using asynchronous drivers like capybara-webkit, you need to watch out for race conditions. The page may still be loading (or updating via Ajax) when first is called, so the input element may not have appeared yet.
Solution: use find("input[type='checkbox']").set(true) instead of first. This will cause Capybara to wait up to two seconds for the input to appear before giving up and raising an error, instead of immediately returning nil.
I wrote more about writing asynchronous tests in a blog post.
Hidden Elements
Because the default driver (rack-test) doesn't parse CSS or run JavaScript, it doesn't understand which elements are hidden or visible. This means that you can interact with hidden elements that real users can't click on or fill in.
On the other hand, drivers like capybara-webkit know which elements are actually visible to the user. By default, Capybara ignores all elements that it knows are hidden.
Solution: use find("input[type='checkbox']", visible: false).set(true)
Note that this won't work if the element is actually visible, and that it's probably better to figure out why the element is hidden. After all, if capybara-webkit can't find it, your users probably can't, either.
You can read more about how Capybara handles visibility on the elabs blog.
So, silly as it sounds the mistake I made was in a url - in my set_and_visit method I was visiting 'matches/new' instead of '/matches/new'. When tested, puts page.body was returning an empty string because it couldn't find that url.
Still I'm not sure why test including check 'John Doe' wasn't returning any error like the one with js: true.

Setting focus with Selenium WebDriver

I have a Selenium WebDriver test where I enter some text into a text input box
var input_Note = Driver.Instance.FindElement(By.Id("note"));
input_Note.SendKeys("test");
I then attempt to click on the Save button, but it does not work. I was previously using Coded UI where there is a SetFocus element that points the focus towards whichever element you are targeting. Is there something similar in Selenium?
var button_Save = Driver.Instance.FindElement(By.Id("save"));
button_Save.Submit();
Sometimes depending on how the page is loaded it will exist and then not exist and then exist again. I have found that waiting on the element is a good idea and sometimes will put two waits back to back for the specific element that this will solve this issue(I would say a programming fix for a double wait would be desired...screen flashing too much at that point). This really depends on the load pattern of your application though.
WebDriverWait wait = new WebDriverWait(_driver, TimeSpan.FromSeconds(10));
wait.Until (d=> Driver.Instance.FindElement(By.Id("save")));
I would also utilize the .click if it is a button. In general it should be a submit action, but it doesn't always have to be a submit action. There may also be situations where you might need to gain the focus...which shouldn't be programmed that way, but in case it is you can utilize the Actions class and move the mouse to the element and then perform a click action on the element.
//C# example:
OpenQA.Selenium.UI.Interactions.Actions actions = new OpenQA.Selenium.UI.Interactions.Actions();
actions.MoveToElement([Instance of Web Element goes here]).Perform();
actions.Click([Instance of Web Element goes here]).Perform();
In general you could just use the actions.Click, but figured I would give both.
One of the above should work just fine. If it does not work please provide a specific error message you get with Selenium and the specific html structure of the page being utilized.

Why focus an input on page load instead of inline?

Almost all web pages that I see designed to set the focus to an input box add the code into a body onload event. This causes the code to execute once the entire html document has loaded. In theory, this seems like good practice.
However, in my experience, what this usually causes is double work on the user, as they have already entered data into two or three fields and are typing into another when their cursor is jumped back without their knowledge. I've seen a staggering number of users type the last 2/3 of their password into the beginning of a username field. As such, I've always placed the JS focus code immediately after the input to insure there is no delay.
My question is: Is there any technical reason not to place this focus code inline? Is there an advantage to calling it at the end of the page, or within an onload event? I'm curious why it has become common practice considering the obvious practical drawbacks.
A couple thoughts:
I would use a framework like jQuery and have this type of code run on $(document).ready(.... window.onload doesn't run until everything on the page is fully loaded, which explains the delay you have experienced. $(document).ready(... runs when jQuery determines the DOM has been loaded. You could probably write the same sort of logic without jQuery, but it varies by browser.
I prefer to keep my Javascript separate from my HTML because it allows for a cleaner separation of concerns. Then your behavior is then kept separate from your document structure which is separate from your presentation in your CSS. This also allows you to more easily re-use logic and maintain that code — possibly across projects.
Google and Yahoo both suggest placing scripts at the bottom of the html page for performance reasons.
The Yahoo article: http://developer.yahoo.com/performance/rules.html#js_bottom
You should definitely place the script in the appropriate place if it means the correct user experience -- in fact I would load that part of the script (Used for tabbing inputs) before the inputs to ensure it always works no matter how slow the connection.
The "document.ready" function allows you to ensure the elements you want to reference are in the dom and fires right when your whole document dom is loaded (This does not mean images are fully loaded).
If you want you could have the inputs start out as disabled and then reenable them on document ready. This would handle the rare case the script is not ready yet when the inputs are displayed.
Well if you call it before whole page has loaded you really don't know if the element already has been loaded when you make your call. And if you make your call in pre-hand you should check if the element really exists even if you know it always should.
Then to make the call inline, which might seem ideal. But on the other hand it's really bad if a page takes that long to load that you can make several inputs during the loading phase.
Also you could check if input has been made etc.
Also it is possible to check if any input on page contains focus if($("input::focus, textarea::focus").length)... and otherwise set focus on desired input.
Use the autofocus HTML attribute to specify which element should initially receive focus. This decouples JavaScript and gracefully degrades in older browsers.

Why do textfields become disabled in IE6 for no reason?

I have made few changes on this huge JSF page, which is full of Javascript as well. I dont know which change make the problem happen.
The problem is: after some Javascript is executed, all the text fields in the page become readonly. The problem is not occurring in IE7 nor in Firefox. I have debugged all the javascript, there is no errors thrown! And there is nothing telling the fields to become readonly, since its working correctly in IE7.
Not sure what the problem is, could be CSS related? or Javascript? And why is it happening on IE6 only?
Note: "Don't support IE6 is not an option"
While IE may be buggy make trouble in some situations, I'm quite sure this is not an IE bug.
How do you tell the fields are read only? Do you get any optical confirmation or is it just that you can't click them any more? In that case, I'll bet you a beer that is's some invisible DIV or other layout element that, due to some CSS setting, squeezes itself above the input fields.
Try the IE developer toolbar to find out whether it's a layout problem.
If they are really disabled as in <input disabled> you need to show some JavaScript or (better) a link.
Still not sure what happened with that build, but what i was sure about is all the Ajax modifications i did was responsible for the problem.
The scenario was like:
Fill textfield1 (hit getValues1 , then hit a validate Ajax)
Fill textfield2 (hit getValues2 , then hit validate on both values together)
Fill textfield3 (hit getValues3 , then hit validate on all three values)
And a forth time again the same scenario. The page was built by a new to JSF guy, and it was very huge. I took long time refactoring it. But now its much better, each text field still have a getValues Ajax, but instead of validating them after getting all the values, i filter the allowed values on the server by sending the chosen criteria
The scenario now:
Fill textfield1 (hit getValues1 Ajax)
Fill textfield2 (hit getValues2 Ajax with value of 1, and get only allowed values)
... etc
The problem seems to be an Ajax racing conditions and at some moment IE6 was hanging or stuck in a deadlock, im not sure.
Lesson learned, "Refactoring once may take a week, but without every single issue will take longer"
um... don't support IE6??? ;)
Suggest disabling your CSS and seeing if the problem goes away. I'm not aware of any CSS tags that can disable a field, though.
Other than that, debugging is your only option. Remove all your .js and add it back in line-by-line until something breaks.
It will probably be hard for us to help you without seeing some code.
See if the HTML for the page has the 'disabled' attribute set on those INPUT elements. If so, then javascript is being used to enable the elements after the page has loaded. This is a not-uncommon technique to keep users from prematurely trying to interact with a page before all scripts have loaded.
If that's what is happening, then what you've probably done is break the way the script recognizes which elements need to be enabled. Since this is only happening on IE6, it sounds like the script might be doing some esoteric DOM navigation, which broke as a result of changes to the markup or CSS.
Unfortunately this is something you'll have to debug by reverting back to previous versions until you identify the change you made that broke the page.
Based on the other answers here, and some of your comments to them, it seems there is a JavaScript function in your page that sets elements to be enabled or disabled.
In order to help, we would have to see your code. Here is something you can do yourself, though, that would solve your problem:
Find that function (or ANY function) that sets elements in your page to disabled or enabled.
Depending on your development environment, there are different ways to do this, but somehow add a breakpoint there at the function.
Load the page.
Whenever that function is called, code execution will stop at that function. Whenever it stops, make sure that it was supposed to be called (and watch the call stack).
Eventually, you'll hit that breakpoint at a point where you weren't supposed to. Look at the call stack to see what caused it (which function resulted in a call to this function).

Categories

Resources