How do I reliably check the current page after navigation in Selenium WebDriver? - selenium-webdriver

In my web tests using Selenium WebDriver and IEDriverServer.exe 2.32.3.0, I need to check the title of the current page after navigating to a certain URL. Here's the code:
_webDriver.Navigate().GoToUrl("...");
Assert.That(_webDriver.Title, Is.EqualTo("..."));
This sometimes works, but sporadically breaks - the title is not as expected (but still the one from the page before).
I've read on StackOverflow (C# Webdriver - Page Title assert fails before page loads) that IWebDriver.Title property does not auto-wait for navigation to complete (why doesn't it?), but instead you need to manually wait using the WebDriverWait API.
I implemented manual waiting for the title:
var wait = new WebDriverWait(_webDriver, TimeSpan.FromSeconds (3.0));
wait.Until(d => d.Title == expectedTitle);
However, this sometimes waits for 3 seconds, then throws a WebDriverTimeoutException. The build agent running the code is quite fast and the web site I'm testing is trivial (just starting development), so I'm quite sure that it can't really take 3 seconds to navigate. I noticed that on the other StackOverflow question, the original poster also got the WebDriverTimeoutException and just caught and ignored it.
I found that solution a little flaky, so I tried a different workaround. I gave the <title> attribute an ID in my HTML and used IWebDriver.FindElement, which is supposed to wait for the page to complete:
Assert.That(_webDriver.FindElement(By.Id(ViewIDs.Shared._Layout.Title)).Text, Is.EqualTo(page.ExpectedTitle));
At first, that seemed to work. However, it doesn't reliably, it sometimes throws:
OpenQA.Selenium.NoSuchElementException : Unable to find element with id == _Layout-title
at OpenQA.Selenium.Remote.RemoteWebDriver.UnpackAndThrowOnError(Response errorResponse)
at OpenQA.Selenium.Remote.RemoteWebDriver.Execute(String driverCommandToExecute, Dictionary`2 parameters)
at OpenQA.Selenium.Remote.RemoteWebDriver.FindElement(String mechanism, String value)
at OpenQA.Selenium.By.FindElement(ISearchContext context)
at ...
(I also tried upgrading to WebDriver/IEDriverServer 2.33.0.0; but in that version, the text of the <title> tag is always empty...)
Hence my question. How do I reliably check the current page after navigation in Selenium WebDriver? Is there a good pattern that works?

I just solved it with stuff I derived from something I found on CodeProject:
private void WaitUntilLoaded()
{
var wait = new OpenQA.Selenium.Support.UI.WebDriverWait(driver, TimeSpan.FromSeconds(%));
wait.Until(x =>
{
return ((IJavaScriptExecutor)this.driver)
.ExecuteScript("return document.readyState").Equals("complete");
});
}
According to w3schools it works for most popular browsers.
As I presently test on Firefox I ended up on Mozilla's own page about how to recognise a page as loaded. IMHO read worth to avoid dragons.
That gave me
wait.Until(p => p.FindElement(
By.Id("somethingThatIsDisplayedWhenMyAsyncronousStuffIsFinished")
).Displayed);
which saved my day.

I have run into very similar issues. I still have not been able to tell why but often if you try to use an element without doing a isElementPresent check it will fail occasionally. My solution is mildly "expensive" but I have not found a reliable alternative as yet.
My example is in java, shouldn't be hard to translate but I don't have the libraries.
waitForElement("_Layout-title", 45);
then continue with your code
Assert.That(_webDriver.FindElement(By.Id(ViewIDs.Shared._Layout.Title)).Text, Is.EqualTo(page.ExpectedTitle));
This tries a set number of times, in this case 45, to find the element. Once id=_Layout-title is present it will continue to the next line of code and do the assert. While it isn't perfect, it did make my test much more stable.

Related

CodeceptJS/Puppeteer only sees elements during paused sessions

I'm having a very frustrating problem with testing a React app using CodeceptJS and puppeteer - it only finds elements with a custom locator only when in paused mode.
My custom locator is data-test-id. I'm targeting elements using I.seeElement("$id-of-element-here") and I.seeNumberOfElements("$test-id", X).
This works perfectly when my tests are paused and I'm manually moving onto each step of the test, but does not work when the tests are executing from start to finish - targeted elements are simply not found.
Sometimes I can counter this with I.wait(X) or I.refreshPage() but I'm now running into a case where none of this helps.
I do see the data-test-id attributes in the HTML using both Chrome's and Chromium's dev tools. There are no typos either.
There's not much point in showing examples of targeted elements, as the problem seems to happen at random, I haven't been able to see any pattern of where/when this happens.
These are the settings of the custom locator plugin, in codecept.conf.js:
plugins{
...
customLocator: {
enabled: true,
attribute: 'data-test-id',
},
...
}
Any help will be appreciated! :)
May waitForNavigation is a way to go?
https://codecept.io/helpers/Puppeteer/#configuration
https://github.com/puppeteer/puppeteer/blob/main/docs/api.md#pagewaitfornavigationoptions
Solution:
I was running the assertions in question in a rather big within block (link), so I was ending up looking for something within an element that was no longer on the page.
It appears that during a pause(), you can find and operate on elements that are visible at the moment and the within blocks don't matter.
That's the only way I can explain why, in this situation, an element can be detected during a pause but not during the actual execution of the test from start to finish.
As soon as I moved the assertions out of the within block, everything was normal and behaved as expected.
Apologies for the confusion - learning every day... :)

Why explicit wait is waiting for entire wait time even though element is visible/clickable before the wait time is over

I have given a wait time for 60 sec, and i am using wait until element to be clickable/visible but script is waiting for whole 30 secs even though the element is visible on UI and also clickable?
I tried using latest selenium version, tried using different waits also using different locators. but it did not work
The reasons could be in:
The element belongs to iframe so you need to switch to the iframe prior to attempting locating anything inside it
The element belongs to Shadow DOM so you need to locate ShadowRoot object, cast it to the WebElement and find the sub-element you want to click
Your locator is not correct, try getting the page source and saving it to a file. Once done use your favourite browser developer tools to locate the elemen
The syntax of your Explicit Wait is not correct. Check out Explicit Waits and How to use Selenium to test web applications using AJAX technology for code examples
Going forward consider adding page source and your code to your question as the chance you will get the comprehensive answer will be much higher, otherwise we have to go for "blind shots"

Is it a good idea to iterate through several browsers in one test using Selenium WebDriver?

I am trying to run a simple test on multiple browsers, here is a mock up of the code I've got:
String url = "http://www.anyURL.com";
WebDriver[] drivers = { new FireFoxDriver(), new InternetExplorerDriver,
newChromDriver() };
#Test
public void testTitle() {
for (int i = 0; i < drivers.length; i++) {
// navigate to the desired url
drivers[i].get(url);
// assert that the page title starts with foo
assertTrue(drivers[i].getTitle().startsWith("foo"));
// close current browser session
drivers[i].quit();
}// end for
}// end test
For some reason this code is opening multiple browsers seemingly before the first iteration of loop is completed.
What is actually happening here? and what is a good/better way to do this?
Please understand that I am by no means a professional programmer, and I am also brand new to using Selenium, so if what I am attempting is generally bad practice please let me know, but please don't be rude about it. I will respect your opinion much more if you are respectful in your answers.
No it's not.
In fact, most of the test frameworks have convenient ways to handle sequential/parallel executions of test. You can parametrize test class to run the same tests on multiple browsers. There is an attribute in TestNG called Parameters which can be used with setting.xml for cross browser testing without duplicating the code. An example shown here
I would no do that.
Most of the time it is pointless to immediately run your test against multiple browsers. Most of the problems you run into as you are developing new code or changing old code is not due to browser incompatibilities. Sure, these happens, but most of the time a test will fail because, well, your logic is wrong, and it will not just fail on one browser but on all of them. What do you gain from getting told X times rather than just once that your code is buggy? You've just wasted your time. I typically get the code working on Chrome and then run it against the other browsers.
(By the way, I run my tests against about 10 different combinations of OS, browser and browser version. 3 combinations is definitely not good enough for good coverage. IE 11 does not behave the same as IE 10, for instance. I know from experience.)
Moreover, the interleaving of tests from multiple browsers just seems generally confusing to me. I like one test report to cover only one configuration (OS, browser, browser version) so that I know if there are any problems exactly which configuration is problematic without having to untangle what failed on which browser.

Random Popups While Automating the Webpage

I was attending an interview and he gave me the following scenarios . If I could get an hint as I could not answer the questions.
Assume that there is an application and popups keep coming up all the time. These are not times, its just random. You never know when they are going to come. How to deal with it?
Assume that the script you wrote is fine. But due to network issues the objects in the page are really slow to load or the page itself is taking long time. How do you deal with such a scenario?
Assume that I have 5-6 pages in the application. In all the pages we have certain text fields. In page 1 and Page 5 there is an object which is a text box. I see that what ever whatever identification method (css, xpath, id etc) you take, the values are same. That is duplicates. How do you deal with this scenario?
What is the basic purpose of "data provider" annotation in TestNG. In genral, what is the purpose of testng annotations?
Thanks.
Assume that the script you wrote is fine. But due to network issues the objects in the page are really slow to load or the page itself is taking long time.
How do you deal with such a scenario. In such situation, You should Wait property of Selenium. Implicit Wait or Explicit wait.
Implicit Wait -- Used for setting Timeout for Webpage loading
Driverobject.manage().timeouts().PageLoadtimeOut(units,TimeUnit.SECONDS);
Explicit Wait-- Used for setting Timeout for particular
Webelement FirefoxDriver f = new FirefoxDriver();
WebDriverWait ww = new WebDriverWait(f,Units);
ww.until(ExpectedConditions.CONDITION);
For second question, Anubhav has answered it.
For third, even if elements are same for the page1 and page5, they can be differentiated. First, switch to page to, whose text field you want to interact with, and then interact with that text field.
For forth, dataprovider is an annotation in TestNG using which you can do data driven testing and using TestNG annotations, you can manage test execution flow of your tests. For more details of dataprovider and TestNG annotation, please go here
For third, If you open 5-6 the pages in different tabs of single browser you will get such a duplication problem. That time only one page is visible to the end user. So we can differentiate that element by visibility and can interact with that element using webdriver
List<WebElement> el=driver.findElements(By.xpath("xpath of that text element"));//you can use other than xpath too to identify the elements
for(int i=0;i<el.size();i++)
{
if(el.get(i).isDisplayed())
el.get(i).sendKeys("text you want to send");//any other action you want to perform
break;
}

how to resolve race conditions in webdriver

I have an app that uses a mixture of angular and asp.net. My issue is that the home page is redirected by setting window.location and then the required data and page is requested form the server.
Previously this was not the case and all routing was done via the angular app. However due to requirements the applications routing had to be changed to what it is now.
Now because the application requires a server side request/response (I believe) this is causing a race condition in my tests as I only receive the expected result once in every 5 tests.
At present I am not able to provide code to explain my situation. However, I will be albe to provide some code in a edit later today.
The only code I can provide for now would be the test that is being run. Although I do not believe this would help without the code running the application.
Recent frameworks have this feature where it sets the document.readState of browser to complete and the content is loaded afterwards. Due to this the test may fails as we will be expecting an element to be present.
For such conditions you have to use explicit wait for the element to be present for which you want to take an action after the page is loaded or changed.
Here is an example how we wait for elements in our project (The application is also angularjs, we use Java for webdriver):
In our Webdriver implementation we added:
private WebDriverWait iWait(int timeoutInSeconds) {
return new WebDriverWait(webDriver, timeoutInSeconds);
}
we want to wait for an element to be visible ("Visibility means that the element is not only displayed but also has a height and width that is greater than 0"):
public void waitForElementToAppear(By by, int timeoutInSeconds) {
iWait(timeoutInSeconds).ignoring(StaleElementReferenceException.class).until(ExpectedConditions.visibilityOfElementLocated(by));
}
the ExpectedConditions class provides many other out of the box condition, here are some:
elementToBeClickable
textToBePresentInElement
titleContains
elementSelectionStateToBe
for more, please look at the ExpectedConditions Javadoc
if you need to create your own conditions, you can use ExoectedCondition (no 's') class
ExpectedCondition Javadoc

Resources