Issue with getting Behat test to find "Search" input that is injected into page by jQuery datatables plugin - behat

The following HTML is inserted into a page by the jQuery Datatables plugin:
<label>Search:
<input type="search" class="" placeholder="" aria-controls="datatable-1">
</label>
The existing Behat test I have, which will not pass:
Given I am on "/courses"
And I fill in "Search" with "course"
The resulting error is:
Form field with id|name|label|value|placeholder "Search" not found.
I have tried the following:
Updating the And to And I fill in "Search:" with "course"
Adding variations of a wait When I wait for "Search:" to appear (timeout in 60 seconds)
Adding variation of a wait When I wait for "[type='search']" (timeout in 60 seconds)
This scenario opens up Firefox and I can see the label "Search:" and the search box.
What do I need to do to get this test to pass?

Behat's I fill in "field" with "value" command is awfully slow, I tend to not use it for this reason.
In this case the label matching is probably not working because of the whitespace around the label text. It's expecting an exact text match, but the extra whitespace is throwing it off.
You can avoid using this function with something like the following:
$this->getSession()->getPage()->find('css', 'input[type=search]')->setValue('course');
If the element is not available when the page loads, you will need to wait for it. I note that you mention that waiting for the label text times out, so you should check to see if the element you're interested in is inside an iframe. In this case, you need to use the switchToIFrame command before selenium can interact with the elements inside the iframe.
For example:
//Switch to iframe with id 'iframeID'
$this->getSession()->switchToIFrame('iframeID');
//Do some stuff with the elements contained in the iframe.
//Switch back to parent iframe.
$this->getSession()->switchToIFrame(null);
One more thing to note is that if there is a hierarchy of iframes, you need to switch one level at a time.

Related

Trouble getting an element to be clicked using Selenium

I am trying to go to the below URL
https://twitter.com/explore
Enter HBO Max in the text box which I locate using
By.cssSelector("input[placeholder='Search Twitter']")
and then I want to select the HBO Max option that appears in the dropdown. My locator for the element to be selected is
By.xpath("//div[#role='option']//li/div/div[2]")
Sometimes the element gets clicked and I go to the new page, sometimes not. I have in my framework waited for the element to be clickable using WebDriverWait. The element is both visible and enabled because I print these values before I click the element.
Additional debugging steps performed -
Click using JavaScript seems to have the same behavior.
I believe I am using the right locator because the mouse event gets generated for this element.
Thread.Sleep seems to work suggesting that perhaps a timing issue
Any inputs would be great.
try:
myElem = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, 'ID')))
print("Page is ready!")
except TimeoutException:
print("Loading took too much time!")
Try this !
what it does : It wait until the specific element of the site is loaded. If it takes more time than specified will just give you an output as "loading took too.........."
You can modify the time required to wait.

Selenium wait for element to reload

I'm trying to do the following:
I have a page that has a list of comments (each comment is a div and the list is a div containing all of these).
There's a button at the end of the page to load more comments. These comments are load as an "infinite scroll". They are appended to the ones present.
I have to perform in Selenium a click to this button to bring more comments and then wait until the new comments are loaded.
How do I do this? I have no way of differentiating the new comments from the old ones. Is there a hook to know when an element changes? I mean, when an element gets added more elements to it's children.
I don't know about a hook; Selenium seems to implement these waits with "polling" rather than hooks.
So, can you wait on a condition, the condition being that the list contains the expected new number of comments?

(Wait doesn't work) Selenium Java <a> Element not interactable

Yes, already tried with all kind of waits.
I have to click on the big "Dress" block on this site: http://automationpractice.com/index.php
I CAN get the /a> and the /li> elements with Xpath, but none of them are ever "clickable" or "visible"
The following does work but I need a more "use like" solution
((JavascriptExecutor)driver).executeScript("arguments[0].click();", driver.findElement(By.xpath("//a[#title=\"Dresses\"]")));
Again, already tried with waiting until clickable and visible, but it just timeout after 2 minutes.
The issue is that there are two elements that match your locator. Since you are using .findElement (singular), it returns the first one which happens to be the one that is hidden and stays hidden unless you hover the first nav item, "Women".
There are two ways to work around this:
Keep the same locator, use .findElements (plural) and click the second element.
driver.findElements(By.xpath("//a[#title='Dresses']")).get(1).click();
^ gets the second element, the first is index 0.
Modify your locator to find the element you want uniquely.
new WebDriverWait(driver, 10).until(ExpectedConditions.elementToBeClickable(By.cssSelector("#block_top_menu > ul > li > a[title='Dresses']"))).click();
I prefer the second because you can add a wait and also because it's a CSS selector. CSS selectors are more compatible, more flexible, easier to read (simpler syntax), etc.
Additional note: The way to avoid this issue is to always check your locators in the browser. I use Chrome because I find it to be the easiest to use and most powerful. You can open the devtools using F12. Press ESC if the Console isn't shown. In the console you can test XPaths using $x(), e.g. $x("//a[#title='Dresses']") returns 2 elements. You can test CSS selectors using $$(), e.g. $$("#block_top_menu > ul > li > a[title='Dresses']") returns only one element.

Robot Framework- Loading Spinner selector

I have this problem where I have to validate if a loading spinner is present, it's present for about 1 second on the page, i have found the xpath selector of the loading spinner but selenium library could not find it is there another way to find out a selector of something that dissapears after a short while? Note: The xpath is definitely correct. There is no id on the loading spinner either.
This is the code i have tried
Validate Loading Spinner
Wait until page contains xpath=//*[#id="app"]/div/div[1]/div[3]/div/div/div/div/svg
I have also tried Element should contain and Page should contain but that does not find the locator.
You should be using one of the keywords that is validating an element is present - Wait Until Element Is Visible, or Wait Until Page Contains Element - both of which support a timeout argument, for how much to wait.
Afterwards, you'd better use the opposite keyword - Wait Until Element Is Not Visible, to make sure the spinner disappears and you can continue with the test.
There is a problem with your locator - xpath has some issues if the element is svg, most of the times it can't address it directly. So instead of specifying it explicitly in the path, look for a node whose name happens to be "svg"; e.g.:
xpath=//*[#id="app"]/div/div[1]/div[3]/div/div/div/div/*[local-name() = "svg"]
(^ changed the last element in the path)
Slightly offtopic - try to have less rigid locators - this one specifies an absolute path from the element with id "app" and down (a div child, then its first div child, then that one's third div child, and so on and so forth). If the element structure changes even slightly, the locator will stop working (say, in a bug fix, or re-positioning it, or just with using a HF of an JS library).
Try to find an element that's 1-2 levels higher than your target svg - by a solid class value, or structure that's unique, and use it as an anchor.
I reckon you used wrong keyword
Validate Loading Spinner
Wait until page contains ELEMENT xpath=//*[#id="app"]/div/div[1]/div[3]/div/div/div/div/svg
Both work:
Validate Loading Spinner
wait until page contains element xpath=//*
[#id="app"]/div/div[1]/div[3]/div/div/div/div/*[local-name() = "svg"]
and
Wait until page contains ELEMENT xpath=//*[#id="app"]/div/div[1]/div[3]/div/div/div/div/svg
I had a very similar issue

Robot Framework+Selenium: how to avoid "stale element" error (flaky test)?

I'm using Robot Framework and Selenium to test a website that has a language selector. I need to be able to select a language and then verify the page has actually changed to that language.
Since after choosing a new language the value in the lang attribute of the <html> tag changes, I decided I would use that to validate the language has been successfully changed. But I'm getting flaky results, as my test sometimes passes and sometimes doesn't.
This is the definition of the keyword I'm using:
CHANGE LANGUAGE
[Arguments] ${lang}
Select From List By Value ${LANGUAGE SWITCH} ?hl=${lang}
Wait Until Page Contains Element css=html
${doc lang} Get Element Attribute css=html#lang
Should Be True '${doc lang}'=='${lang}' timeout=15s
Since I have to execute this keyword quite a few times (one per each available language), I keep getting pretty often the dreaded "stale element" error: | FAIL | stale element reference: element is not attached to the page document.
I read through this article and a few other questions in here and understand this could happen if an element reference is updated after obtaining it. However, I'm not sure how exactly I should modify my keyword to avoid getting this error.
Using the information that everyone has so kindly provided, I may have found a potential fix (not sure if it's robust enough not to throw the exception anymore, but after a few test runs they have all passed): I added a "Wait Until Keyword Succeeds" and moved the language validation to a new keyword:
VALIDATE PAGE LANGUAGE
[Arguments] ${lang}
${doc lang} Get Element Attribute css=html#lang
Should Be True '${doc lang}'=='${lang}'
CHANGE LANGUAGE
[Arguments] ${lang}
Select From List By Value ${LANGUAGE SWITCH} ?hl=${lang}
Wait For Condition return document.readyState=="complete"
Wait Until Keyword Succeeds 5 5s VALIDATE PAGE LANGUAGE ${lang}
Then I call this "CHANGE LANGUAGE" keyword as many times as languages I need to test.
I added this as an answer instead of a comment so I could show the code in a more readable way.
In order to wait for a page to be ready to test after a user action (clicking a link or button, for example), the algorithm I've found that seems to be almost bulletproof is this:
get a reference to the html element
perform the action that will cause the page to change (eg: click a link or button)
wait for the html element to go stale - this signals that the refresh has started
wait for document.readyState to be "complete"
Step 4 may not be necessary, but it doesn't hurt.
This has worked extremely well for my team. This can still fail since you might have some async javascript that runs after document.readyState has been set, but there's simply no generic solution to that.
If your pages have a bunch of async javascript, you'll have to come up with your own scheme to know when the page is finally ready to be tested. For example, the last job to complete could set a flag, or you could wait until there are no pending async jobs, etc.
I'm not sure if you can do the above with robot keywords since it relies on the selenium staleness_of condition. It's pretty easy to implement in python, though.
The inspiration for this solution came from this blog post: How to get Selenium to wait for page load after a click
If you use my page object library for robot, this is built-in as a context manager.
As highlighted, a Stale Element error typically means that between the element retrieval and the corresponding action the element changed. Often this is due to a page refresh.
For this reason it is important to invest in a robust waiting approach. Not guessing that your page/application has completed loading, but instead knowing it has completed. This will not only prevent Stale Element errors but also speed up your tests as you're not unnecessarily waiting.
As the Get Element Attribute ${DOCUMENT}#lang is causing the stale element error and the Select From List By Value ${LANGUAGE SWITCH} ?hl=${lang} is causing the page refresh, then that leaves the Wait Until Page Contains Element html as your waiting approach.
As the <html> tag is always present and the first to be loaded in the DOM, this is not the best tag to wait for. I'd advise something unique for the loaded page or the last element of that page. Though I have to stress that this still constitutes to guessing the page has loaded.
It is better to invest in a robust waiting approach. Especially if your application is using a framework like Angular, React or jQuery then you have several Javascript markers to help you with this. For some frameworks there are even custom Robot Framework Libraries that support their specific markers.
Should your application not use a framework, then talk to your developers and have them develop this for you. Simplest would be a visible spinner, but a Javascript function that returns True will work just as well.
I have created a custom keyword when ever i want to click an element or perform and action i would call this custom keyword . This custom keyword uses the built-in keyword 'Wait Until Keyword Succeeds' which runs the specified keyword and retries if it fails. through this built-in keyword the number of retry's and the time to wait before trying to run the keyword again after the previous run has failed can be configured.
This custom keyword would call another custom keyword where three SeleniumLibrary keywords would be called. The first one would Waits until element locator is enabled keyword, which would wait until the element is not disabled nor read-only. Once the element is enabled then focus would be taken to the element where we are going to perform action. Finally perform the action. All these precautions has prevented me from Stale Element error.
HighLevelKeyword_Identify And Click Element
[Arguments] ${locator}
Wait Until Keyword Succeeds ${RETRY_ATTEMPTS} ${RETRY_AFTER} Identify And Click Element ${locator}
Identify And Click Element
[Arguments] ${locator}
Wait Until Element Is Enabled ${locator}
Set Focus To Element ${locator}
Click Element ${locator}