Here's an example: http://screencast.com/t/1PrhUrDSMG
In that 1 second that message is on the screen. 2 round trip Selenium commands to first check if the message is on the screen, then to get the message text can take longer than a second when using a 3rd party selenium grid provider that's on an outside network (like Sauce Labs or Browserstack).
Doing it before using a Selenium polling loop.
Before I had a simple polling loop that checked for this error message.
end_time = datetime.now() + timedelta(seconds=10) while datetime.now() < end_time: err_msg = self.webdriver.find_element_by_id("message") if err_msg.is_displayed(): # This could be subjected to stale element errors # if element disappears between the 2 selenium calls # needed to check if the element is visible, then to # get the text. text = err_msg.text if text == 'Success': break else: raise PageError(text) # needed a sleep to prevent flooding the network # connection to SeleniumGrid with traffic, however, # the element can disappear during this time. time.sleep(0.5)
It had many issues like the element disappearing off the screen before it could be found, or the element properties changing before I can read the text causing a StaleElementReferenceException. Since sending commands using selenium is very slow, it's hard to do polling on element visibility or content for element, because the properties change and disappear off the screen during the period the Selenium commands were still in transit or during our sleep interval.
Pushing the polling for success / error messages to the browser side.
To solve this issue, we can have a faster polling for that disappearing message element that's entirely in JavaScript.Injecting a JavaScript Interval for fast polling.
First we create a method that'll inject a javascript polling interval.
This will first clear a latch variable. Then create a polling interval that'll fire off every 100ms, which is a lot faster than if we polled using selenium. What this does is when the message appears on screen (in this case marked by the opacity going higher than 0 from the fade in effect, it'll automatically set the latch to True.def inject_javascript_polling_latch(driver) js_command = """ window.__TEST_message_listener_latch = false; window.__TEST_message_listener = window.setInterval(function(){ if (document.getElementById("message").style.opacity > 0) { window.__TEST_message_listener_latch = true; window.clearTimeout(window.__TEST_message_listener); } },100);""" driver.execute_script(js_command)
Checking the latch is set
After the latch is injected, I can simply check if the latch is set on my wait loop, which is running slower because it has to wait on a round trip from the machine running the test and the machine running the browser.wait_condition = lambda: self.webdriver.execute_script("return window.__TEST_message_listener_latch_message") == True wait_until(wait_condition)
And there you have it. A simple way to shift the polling loop from the test machine that has to deal with round trip delays, to the browser that'll execute against the page itself with no delays.
9 comments:
same thing is happening in our application.But i am writing tests in c#. Your code is in python.Please help me with c# code.
Hi david Lai,
Now i am able to check the notification message.But i am not able to get text from that element.The element is inside a span tag .same span tag shows 3 different messages while add,update,delete. I tried to assert text in span while adding but i am not able to get text from that. Help me regarding this.
You can also use the technique to save message to a JavaScript variable.
You can use the innerText or textContent property (depending on which browser), and save that to another JavaScript global, alongside the JS latch.
I am able to get text now. I achieved that with default wait property wit polling intervals set.
But I am also curious to get the javascript code you have provided in C#.
I'm not familair with the webdriver c# syntax.
But everything in JavaScript should stay the same, but may have differences depending on which browser you use.
The idea is you can craft JS statements to save values into global variables. Then you can use executeScript to return those back when you poll on them.
Thanks David. I will try
i got it now.used jquery in this context.without using latch, i am able to get inner html of the notification message.Thanks for make me think in different approach.
hi,
could u please help me in the polling code in c#...i'm having the same issue of fading the text message before it is located.
You should be able to use the JS code verbatim since that is injected. Only diff between Python and C# in this case is how you define your method signatures.
Post a Comment