teodesian / Selenium-Remote-Driver

Perl Bindings to the Selenium Webdriver server
174 stars 90 forks source link

How do I get the value from a Toast message using Selenium::Remote::Driver? #108

Closed moezhirani closed 10 years ago

moezhirani commented 10 years ago

On a certain action , a toast message pops up on the website that stays there for as much as 5 seconds. I need to get some information from this toast as it determines the next steps for my test.

Please help, Thanks, Regards, Moez Hirani.

gempesaw commented 10 years ago

That's really going to depend on the implementation of the 'toast message,' - is it using HTML5 notifications? Without more information, it's going to be really hard to provide assistance.

moezhirani commented 10 years ago

Its using this project for notifications - https://github.com/CodeSeven/toastr

gempesaw commented 10 years ago

You'll probably want to interact with toastr via javascript commands ($driver->execute_script) instead of racing the toast timeout. Perhaps the toastr variable exposed by that library has a function that returns all toasts?

From the readme, toastr accepts an onShown callback that you could use to put the text somewhere where your test will be expecting it. I played with the toastr demo a little bit - there's a subscribe function on the toastr global that lets you register a callback that gets called with the toast object, which has all the information about the notification being toasted, including the message.

toastr.subscribe( function (toast) { 
    console.log(toast);
}); 
toastr.success('hello'); // Object {toastId: 1, state: "visible", startTime: Fri Mar 14 2014 14:51:17 GMT-0400 (EDT), options: Object, map: Object}

Check out the map property of the toast object that the subscribe callback gets as its argument.

moezhirani commented 10 years ago

Thanks a lot gempesaw , I feel much more confident now that I will be able to grab the message in the notification. This was really very helpful. Best,Moez

Rashmi-Nuviso commented 8 years ago

hi Moez ,

can you please help me to solve this issue .

am trying to get the toast message for validation .

But am unclear about the steps .I have an use-case where invalid username and password should throw an error "Bad credentials". this error message is coming from the server and captured as toast message for the UI to display it to the user .

moezhirani commented 8 years ago

Hi Rashmi,

I basically used a locator like - //[@id="toast-container"]/div/div* - to identify the toast message. a 'find' for that locator followed by ' _gettext' worked fine for me. You may need to look through the code to find out a good locator for your toastr object.

Finding the element was sometimes challenging (the toastr in my case showed up after clicking a 'submit' button) , but I added a wait that lets jquery to finish before looking for the element. For me, clicking the 'submit' was causing some background processing to occur.

If you need a wait, then wait_for_jquery can be a helper function in your framework that basically works by polling for the value of $driver->execute_script('jQuery.active')' . As soon as this value is 0 , it means the jquery has finished processing and you can continue with the test.

On Mon, Feb 8, 2016 at 2:56 AM, Rashmi-Nuviso notifications@github.com wrote:

hi Moez ,

can you please help me to solve this issue .

am trying to get the toast message for validation .

But am unclear about the steps .I have an use-case where invalid username and password should throw an error "Bad credentials". this error message is coming from the server and captured as toast message for the UI to display it to the user .

— Reply to this email directly or view it on GitHub https://github.com/gempesaw/Selenium-Remote-Driver/issues/108#issuecomment-181245435 .

Rashmi-Nuviso commented 8 years ago

Thanks a lot Moez and gempesaw for getting back on this quickly :)

your comments helped me to locate the toast-element. for those who need help on this am pasting the python snippet here .

getErrorMsg = WebDriverWait(self.driver, 30).until(EC.presence_of_element_located( (By.XPATH, './/*[@id="toast-container"]/div/div[1][@class="toast-message"]'))) logging.info(getErrorMsg.text)

hope it helps .!!!

Cheers !! Rashmi BS.

JeheenC commented 8 years ago

Hey Guys!

I am facing similar situation, the web page that i am trying to automate using selenium IDE.So as i am trying to use the page to submit a request and when it's done submitting it throws a toast message for quick 4-5 secs at most. I have tried to to capture it using command = 'waitForElementPresent' target = 'css=span.md-toast-text.ng-binding' then i used command = storedtext target = 'css=span.md-toast-text.ng-binding' value = 'confirmation_ID'

Then i tried using the above info in the search box but that does not do it for me. And all the things you guys have mentioned isn't making any sense to me as i am not a developer/programmer as my background is in QA and this is something very new to me actually my second day messing with selenium ide. So can you guys break this down to me in simplest way as to how i can go about capturing the toast and use it to search for my request..

Any help what so ever in a promptly manner will be greatly appreciative.

Thanks in advance.

Jeheen

moezhirani commented 8 years ago

Hi Jeheen,

Could you please paste in the code that you are using ?

Moez.

JeheenC commented 8 years ago

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

New Test (after the submit is when the toast gets displayed.)
New Test
open /#/login
verifyTitle AiM CRM
verifyElementPresent id=username
type id=username sample@aiminspections.com
verifyElementPresent id=password
type id=password testing
verifyText //button[@type='submit'] Log In
click //button[@type='submit']
verifyTitle AiM CRM
verifyElementPresent link=New Request
click link=New Request
waitForText css=span Inspection Request
click id=customer-name
click id=select_option_161
click id=request-type
click id=request-type
click css=#select_option_165 > div.md-text.ng-binding
type id=input_7 James Honda
type id=input_8 12345
type id=input_9 SL12345
type id=input_10 Mount rd and 13 mile
type id=input_12 Detroit
click css=#select_value_label_2 > span.md-select-icon
click css=#select_option_68 > div.md-text.ng-binding
type id=input_15 48212
type id=input_26 1
click css=div.md-off
type id=input_36 2014
type id=input_37 Honda
type id=input_38 civic
type id=input_39 se
type id=input_40 5XDEG55679FSFSDF
type id=input_41 SL1234
click css=div.crm-color-dropdown-color.crm-color-dropdown-no-selected-color
click xpath=(//button[@type='button'])[5]
click name=request.preferredDays[]
click document.inspectionForm.elements['request.preferredDays[]'][2]
click document.inspectionForm.elements['request.preferredDays[]'][4]
click css=md-checkbox[name="sameAsDealerLocation"] > div.md-container.md-ink-ripple
type id=input_35 JEHEEN TEST
click id=submit
waitForElementPresent css=span.md-toast-text.ng-binding confirmation_ID
storeEval storeVars['span.md-toast-text.ng-binding'] confirmation_ID
click id=basic-search-input storeVars
click id=submit
click //button[@type='button']
Rashmi-Nuviso commented 8 years ago

Hi Jeheen ,

you can try to locate the parent element first in the dom tree

as I have mentioned in my code [the one which is highlighted in bold] .

getErrorMsg = WebDriverWait(self.driver, 30).until(EC.presence_of_element_located( (By.XPATH, *'.//[@id="toast-container"]/div/div[1][@class="toast-message"]**'))) logging.info(getErrorMsg.text)

You need to capture this in real-time .

suppose for example on click of an cart icon some item will be added to cart the message which shows up after clicking the cart icon in toast you need to click on that message and inspect it using the firebug tool .

Since that the element where the message will be available will appear only for a few secs obviously you need to add the wait

JeheenC commented 8 years ago

Ok i will try to use the code you have provided. Thanks Rashmi !

Rashmi-Nuviso commented 8 years ago

Jaheen!!

its just an example just follow the steps as i have mentioned in the previous post .my code may not suit your requirements .

JeheenC commented 8 years ago

Rashmi,

so i would use the code highlighted in bold as follows

Command = getEerrorMsg Target = the code in bold

is this correct and add wait statements ...

Rashmi-Nuviso commented 8 years ago

getMsg = WebDriverWait(self.driver, 30).until(EC.presence_of_element_located( (By.XPATH, 'paste your toast Xpath here ]')))

print(getMsg.text)

hope this would help :)

JeheenC commented 8 years ago

thanks and sorry as i have very little exp with dealing coding and what not so therefore i apologize if i sound non techy person.

But none the less thank you so much.

abhishekkumar-tudip commented 5 years ago

I am unable to get the xpath for the toaster message. Can anyone let me know how to get the xpath for the toaster message.

harshwardhan27 commented 5 years ago

I am unable to get the xpath for the toaster message. Can anyone let me know how to get the xpath for the toaster message.

harshwardhan27 commented 5 years ago

I am unable to get the xpath for the toaster message. Can anyone let me know how to get the xpath for the toaster message.

Same problem with me as well.

teodesian commented 5 years ago

Getting xPaths for arbitrary elements on a web page is straightforward.

This will copy the Xpath to your element into your paste buffer, and you can paste it to your heart's content.

The major complication here is that toast messages are an android specific abomination. As such, you will have to use intrusive javascript techniques to grab it's selector, much as described in Gempesaw's earlier comment in this thread: https://github.com/teodesian/Selenium-Remote-Driver/issues/108#issuecomment-37682779

That said, it is generally in your best interest to stop using Xpath selectors. They are easy to fool due to shadow DOM rendering differently on various browsers. CSS selectors are much, much more reliable. Given there are already competing versions of android, this may already be a problem in some cases.