Is waiting needed in Capybara for non DOM-altering Javascript? - ruby

From what I understand of Capybara's autowait feature, it waits for the DOM to change, so I guess it's waiting for all AJAX requests to complete and/or the main frame to finish loading.
I have a test case in which I need to:
fill in a field (name_1)
click a save button
check the object is saved properly
When I fill in the name_1 field, some JS from the app I'm testing fills in other mandatory fields automatically (notably, link_rewrite_1).
Problem is, when I check for the other field to be actually filled, it is not!
I'm thinking the JS that fills the other fields has not had time to complete when the test is run, and the test doesn't wait since there is no AJAX call pending.
Here is the relevant code snippet:
fill_in 'name_1', :with => 'Bob' #some javascript should run and fill link_rewrite_1
find('#link-Seo').click
page.should_not have_field('link_rewrite_1', with: "")
In plain English, I fill in name_1 and expect link_rewrite_1 not to be empty.
I've tried to insert a sleep 1 before the last check, but it doesn't change anything. Since sleep will pause the execution of the entire ruby thread, maybe it just freezes webkit and changes nothing, I don't know.
Am I right in suspecting a timing issue or is there likely something else going on here?

After further debugging, it seems like it is a driver issue. Capybara-webkit just doesn't execute my JS correctly. Works fine with selenium-webdriver.

Related

how to reload page until a button appears using capybara and ruby

I want to click a button after an action and button does not appear until and unless I reload the page. And some times it takes some time to appear the button and I have to reload page for more than once. I don't want to put static delays. So is there a way to achieve following using capybara and ruby:
do
page.evaluate_script("window.location.reload()")
until a button appears
While Mesut's code should work fine, I would re-write it as:
Timeout.timeout(Capybara.default_max_wait_time) do
loop do
page.evaluate_script("window.location.reload()")
break if page.has_selector?(...)
end
end
This will make sure to fail if it will have to wait more than timeout defined in Capybara settings. It can be useful when for example specs are running on the CI server.
Be aware that it can still lead to unexpected behaviors in some drivers, because it can interrupt while some scripts are evaluating.
reoload until page.has_selector? returns true, check this:
while true
page.evaluate_script 'window.location.reload()'
if page.has_selector?("css_selector")
break
end
end

intercepting the onload event fired by the browser in watir

I have a unique situation over here. I have a button on a form which produces a popup if there are some errors in the form. [I know this is not good practice, but the developers of the product would not be changing that behavior!] The form navigates to a different page if all the required fields are correctly populated. Now, I need to write a script in order to click the "Submit" button on the form which either might produce a popup or navigate to the next page.
I have the used the click_no_wait on the "Submit" button and handled the popup using AutoIt as per Javascript Popups in Watir. Now, if all the information is valid and the form navigates to the next page, I use a delay in the script by following some of the techniques described in How to wait with Watir. I am using a Watir::wait_until() to wait in the script.
Now sometimes because of some network issues, it takes time to go to the next page (report-generation) page when the form is submitted and thus the script fails because of the timeout value specified in the wait_until.
I was wondering whether there is a way to intercept the onload event of the HTML page in Watir, since the onload event isn't fired until the entire page is loaded. By that way I could have an accurate estimate of the timeout value and not experiment with it. Thus, my script will pass 100% rather than say 98% right now.
Thanks for any help on this topic.
You could try setting up a rescue for the time out, then looping a reasonable amount of times (2 or 3?) if it encounters a timeout.
E.g.
# All your button clicking and autoit stuff here
i = 0
begin
b.wait_until{ # the thing you're waiting to happen }
rescue TheSpecificTimeOutException
# Sorry I can't remember it, the command prompt will tell you exactly
# which one
if i < 3
i += 1
retry
else
raise
end
end
I'm sure i'll have messed something up in the above, or there'll be more concise ways of doing it, but you get the idea. When it times out, give it another few tries before giving up.

Watir - text_field - watermarked/pre-populated text concatenation

I am a relatively new user of ruby and have witnessed the following sporadic anomaly with entering text into text fields with pre-populated (or watermarked) text.
I have a login page with Email address and password fields.
The Email address field has some pre-populated text which says 'Enter your email address here'
When the user clicks in the text field, the text disappears ready to accept the actual input.
However, on some runs of my ruby/watir scripts I'm finding that the value I wish to enter (using browser.text_field(:id,'name').set 'mylogin') simply gets concatenated with the pre-populated text (I.e. so I see 'Enter your email address heremylogin') and on other runs it does what I expect and just enters 'mylogin')
So far, I"ve only been trying this on Firefox 9.0/Mac OSX so don't know whether it's a peculiarity of the browser, os, or indeed the site under test. The html of the fields in question look like this:
<input name="ctl00$MainContentPlaceHolder$TextBox_email" type="text" id="ctl00_MainContentPlaceHolder_TextBox_email" style="color:#0B404E;border-color:#A4A4A4;border-width:1px;border-style:Solid;font-family:Arial;font-size:15px;font-weight:bold;width:318px;padding: 4px 10px;" class="watermarked" autocomplete="off">
<input type="hidden" name="ctl00$MainContentPlaceHolder$TextBoxWatermarkExtender_email_ClientState" id="ctl00_MainContentPlaceHolder_TextBoxWatermarkExtender_email_ClientState">
Is there an alternative way of inserting text into this field without triggering this anomaly?
Thanks in advance
D
If it's a "sometimes it does this, sometimes it does that" issue, I'd go with it being a timing problem.
Try running the same code through IRB ( http://wiki.openqa.org/display/WTR/IRB )
e.g. browser.text_field(:id => "emailAddress").set("my.email.address#whatever.com")
If that works, refresh the page and do it again with browser.refresh
If it consistently inputs the correct email address using IRB, it's most probably a timing issue.
Test by adding a small sleep to your script just before putting the email address into the field, e.g.
sleep 10
browser.text_field(:id => "emailAddress").set("my.email.address#whatever.com")
If that works, something's changing on your site between the page loading and between when watir interacts with that field. Find out what, and wait for that to happen.
Potentially with something like browser.wait_until{browser.text_field(:id => "emailAddress").value == "The placeholder text"
There is likely some client side code that clears the field. if you view the HTML you might find it. if I was guessing I'd try 'onfocus'' first
when watir fills in the field a lot of things happen very rapidly and the client side code may not get a chance to clear the prior contents.
what I would do is use irb and the .fire_event method to see if you can fire an event that causes the field to clear e.g.
browser.text_field(:id => "emailAddress").fire_event('onfocus')
if you find one that clears the field, then try putting that line ahead of the line in your script that sets the value
another option would be to try .value= instead of .set

Watir and Ajax requests

In my webapp I have a simple textfield. To this textfield I have a jQuery function which will be always executed on every keyup. With this function there is an Ajax request assigned which loads every time the result of the SQL-Query. My code is equivalent to the code of
RailsCasts. Now I'm testing my webapp with Selenium. With this line of code
browser.text_field(:id => 'textfield').set("Search text")
the text will be written and the content will be changed. After it should click on a link which is placed on the dynamic content with this code
browser.a(:id => "link").click
The problem now is that the click event won't be executed. Has somebody an idea what the problem could be? Or maybe an example with Watir and Ajax?
Without an example site to test against it's hard to be sure but I will throw out a few potential solutions for you
If the client side javascript is looking for onkeyup events, you may need to fire one after setting the contents of the field. You can do that via the .fire_event method
You could just be looking at a timing issue. If the nature of the link is changing as a result of the input, it's possible that Watir is firing off the two comments in rapid succession and the client side code is still in the midst of doing it's thing (especially if there is back and forth between the jquery code and the webserver that as happening as that also induces networking delays. You may need a brief sleep between commands (brute force) or to wait for a particular element to assume an expected state (a little more work but also a bit more robust and not subject to breaking is the delay exceeds your sleep duration)
I'd suggest executing the commands manually via IRB (you could just cut and paste from your script as needed) to be able to watch the state of the browser, and note any delay in updating the screen/DOM after a particular action. If stuff works properly in IRB but not when executed via a script it's often taken as confirmation of a timing issue.
If this is the original Watir/Firewatir I would try getting it to hover over the link before it attempts to click it.
I've had this problem previously with links that appear after typing into an "autocomplete" field (i.e. it attempts to guess at the text you want by filtering down from a huge list of possibilities).
Try this:
browser.wait_until{browser.link(:id => "link").present?}
browser.link(:id => "link").fire_event("onmouseover")
browser.link(:id => "link").click
If it works, try it without the .fire_event("onmouseover"), because it could just be that it's trying to click the link before it's visible and failing to do so.
If this is actually a question regarding "Selenium" (wrongly labelled Watir) then ignore all of the above, because I that is an application I've never used.
you can use capybara method.
click_link("link")
for ajax set :js => true in you test case
http://opinionatedprogrammer.com/2011/02/capybara-and-selenium-with-rspec-and-rails-3/

Using Watir on Peoplesoft App: each text field reloads the page

I'm using Watir 1.6.7.
I'm working on developing some regression tests for a PeopleSoft App using Watir and Cucumber. I have run into a few issues with forms in the application.
First, when entering a value into a text_field, the page refreshes when the user clicks outside the text_field. Waiting for the next text_field element to exist is problematic because it may locate the element before the page reloads, or after the page reloads as expected. Increasing the wait time never feels like a good solution, even though it "works".
The second issue is that the page refresh is not triggered until the user clicks outside the current field. In this case, that happens when the script tries to access the next text_field to be populated. One solution here would be to send a or keystroke, but I can feel the script becoming more brittle with every addition like this.
Are there any other approaches that would be less brittle, and not require 2-3 extra commands in between each text_field action?
The play-by-play looks like:
Browser navigates to page that contains the form.
Browser fills in first form field. (fix: send keystroke to cause page refresh, wait_until second field is visible again)
Browser selects the second form field to be filled out. (again, keystroke & wait_until)
Page refreshes, script fails. (resolved)
Browser selects the third form field...
The application started exceeding the 5 second sleep duration, and I did not want to increase the wait time any longer. I wanted to see what would happen if I populated the text field faster using "element.value =" rather than character by character with "element.set ".
This change completely resolved all complications. The page no longer refreshes when entering text, and no long requires a send_keys statement to use TAB or ENTER to move to another field. The form is storing all of the data entered even though there are no refreshes or state saves between fields.
Previous method:
def enter_text(element, text)
element.set text
#browser.send_keys("+{TAB}")
sleep 5
Watir:Wait.until { element.exists? }
end
New method:
def enter_text(element, text)
element.value = text
end
Firstly, there are interesting Wait methods here: How do I use Watir::Waiter::wait_until to force Chrome to wait?
Overall, I don't quite understand your problem. As I understand it your script is working. If you could be a bit clearer about your desires compared to what you already have that would help, as would some sample source code.
If you're looking for ideas on custom waiting you could check for changes in the HTML of your page, form or text field. You could check that the text field is .visible?. You could try accessing the next text_field (clicking it, or setting the value for example), then catch the exception if it can't find the text_field and retry until it doesn't break, which would solve both your problems at once.
Why would clicking outside the current field be a bad solution? Do you absolutely need the next step to be a text_field access? I haven't gotten my head around how the next field only exists when you click outside the current field, but you cause this refresh by accessing the next field.
Edit: Most welcome, and thank you for clearing that up, I think I now understand better. If you allow Watir to invoke its page wait, or force it to, then it will wait for the refresh and you can then find the new text_field. Keystrokes do not invoke ie.wait, so if you send a single keystroke, then invoke a wait then the rest of your script will be responding to the post-refresh state.
I highly recommend the OpenQA page on waiting in Watir. If what you're doing to invoke the refresh does not appear on the list of things that invoke Watir page waits then you need to invoke your own page wait... but you need to do it before the page refreshes, so the cause of the refresh should end before the end of the refresh itself.
I don't know peoplesoft's app well enough to know this, but Does the app display anything for the user while it's processing.. like some kind of little 'loading' graphic or anything that you might be able to key off of to tell when it's done?
I've seen apps that do this, and the item is just an animated gif or png and it is displayed by altering the visibility attribute of the div that contains the graphic. In that instance you can tell if the app is still loading by using the .visible? method on that element and sleeping for a while if it's still there.
for the app I'm testing (which has one of those 'icons') I created a simple method I called sleepwhileloading. all it that is does is use a one second sleep wrapped in a while loop that looks to see if the loading icon is visible. works like a charm

Resources