I am a newbie in automation testing, and m really confused about assert and verify.Since, I am using TestNG, according to my research I came to know that in webdriver, we dont have verify, we have hard and soft assertion. But when I search for it, I get all mixed answers. and nowhere can I find a detailed example.
For soft assertion I saw someone using 'customverification' but when I try to write that in my program I get error, asking to create a class or interface.
Can someone please help me in this. I am studying through internet so its really hard to get correct answers.
Thanks
package revision;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.testng.Assert;
import org.testng.annotations.Test;
public class Six {
WebDriver driver=new FirefoxDriver();
#Test
public void SandyOne() {
driver.get("file:///C:/Users/Sandeep%20S/Desktop/Test.html");
Assert.assertTrue(IsElementPresent(By.xpath("//input[#id='custom']")), "tab was missing");
driver.findElement(By.xpath("//input[#id='custom']")).sendKeys("abcd");
System.out.println("1st program");
System.out.println("blah 1");
System.out.println("blah 2");
}
public boolean IsElementPresent(By by) {
try {
driver.findElements(by);
return true;
} catch (org.openqa.selenium.NoSuchElementException e) {
return false;
}
}
}
If you have an assert that fails the test will be stopped, where for verify the test will be continued and the error will be logged.
Ideally you will have only one assert per test (e.g. the correct page has loaded) and verify will be used to check the information on that page in this case.
Therefore, if the correct page was not loaded, there is no point in checking the stuff on the page is correct.
You can get an idea and a visual example here.
Your test probably fails here:
Assert.assertTrue(IsElementPresent(By.xpath("//input[#id='custom']")), "tab was missing");
because IsElementPresent returns false. One way to avoid that would be:
try {
Assert.assertTrue(IsElementPresent(By.xpath("//input[#id='custom']")), "tab was missing");
driver.findElement(By.xpath("//input[#id='custom']")).sendKeys("abcd");
}
catch (AssertionError ae) {
//ignore
}
However, catching errors is quite ugly code. A better way would be to use WebDriver.findElements(By by) and check if the resulting list is empty or not.
Hard Assertions:Test execution stops as soon as assertion failure found.
Soft Assertions:Test execution continues even if assertion failure found.
e.g. You have 3 assert statements Assert1,Assert2,Assert3
Now if Assert2 fails in case of hard assertion the test will terminate.
In case of soft assertion it will move to next steps in test and then terminate.
You need to instantiate soft assertion as:
SoftAssertions softAssertion = new SoftAssertions();
softAssertion.assertTrue(condition,message)
In your given code snippet hard assertion makes sense since you cannot move to next step to send text until the input box is found.
In given example you don't need to assert element presence. If it's missing the findElement method will throw an error and you will know that it's not there.
If you have elements's Id, use it instead of xpath. This will make the code more readable and faster:
driver.findElement(By.Id("custom")).sendKeys("abcd");
Instead of directly calling the findElement method, it's recommended to use the PageObject pattern and pick elements with annotations, see PageFactory:
public class TestPage {
#FindBy(id = "custom")
WebElement custom;
private WebDriver driver;
public TestPage (WebDriver driver) {
this.driver = driver;
PageFactory.initElements(driver, this);
}
public TestPage inputCustom(String txt) {
custom.sendKeys(txt);
return this;
}
}
#Test
public void SandyOne() {
// ...
TestPage page = new TestPage(driver);
page.inputCustom("abcd");
// ...
}
Related
I am automating a scenario wherein a specific web element might or might not be displayed on the UI. If it is getting displayed, then I want to perform a specific action on it. I am using below logic for the same
try{
if(element.isDisplayed())
{
//perform action on the element if it is visible
}
}
catch(Exception e)
{
}
The code works fine whenever the element is visible on the UI. But during scenarios when the element is not displayed, then 'element.isDisplayed()' waits for the element for 10 seconds (i.e the implicit wait time which I have defined for the driver session).
I want my script to not wait for that 10 seconds for the element to appear, instead just go ahead with further actions. Any idea what approach should I go with here?
It seem like you can achieve with decrease timeout value utilize WebDriverWait.
Try to create a boolean function to check the element presence or not with specific time.
public boolean checkElement(By locator, int seconds) {
boolean find = false;
try {
new WebDriverWait(driver, seconds).until(ExpectedConditions.presenceOfElementLocated(locator));
find = true;
} catch (Exception e) {
// TODO: handle exception
}
return find;
}
Just call with:
By locator = By.name("yourLocator");
if(checkElement(locator, 1)) {
//perform here
....
}
The following imports:
import org.openqa.selenium.By;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
Please delete implicitWait which you've declared before.
I am trying to write a simple fixture that opens the browser and navigates to www.google.com. When I run the wiki page, it passes with all green, but the browser never opens up (I don't think the method even gets called by the wiki). Can someone take a look at my fixture and wiki to see what I am doing wrong? Many thanks in advance,
Here is the Wiki -
!|SeleniumFitness|
|URL |navigateToSite?|
|http://www.google.com| |
After Running -
!|SeleniumFitnesse| java.lang.NoSuchMethodError: org.openqa.selenium.remote.service.DriverCommandExecutor.<init>(Lorg/openqa/selenium/remote/service/DriverService;Ljava/util/Map;)V
|URL |The instance decisionTable_4.setURL. does not exist|navigateToSite?
|http://www.google.com|!The instance decisionTable_4.navigateToSite. does not exist |
Here is the Fixture -
package FitNesseConcept.fitNesse;
import java.util.Properties;
import org.junit.BeforeClass;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.annotations.BeforeMethod;
//import com.google.common.base.Preconditions.*;
//import com.google.common.collect.Lists;
import fit.ColumnFixture;
public class SeleniumFitnesse extends ColumnFixture {
public static ChromeDriver driver = null;
private String navigateToSite = "";
public String URL = "";
public SeleniumFitnesse() {
Properties props = System.getProperties();
props.setProperty("webdriver.chrome.driver", "/home/ninad/eclipse-workspace/chromedriver");
driver = new ChromeDriver();
}
// SET-GET Methods
public String getURL() {
return URL;
}
public void setURL(String uRL) {
URL = uRL;
}
public String getNavigateToSite() {
return navigateToSite;
}
public void setNavigateToSite(String navigateToSite) {
this.navigateToSite = navigateToSite;
}
// Navigate to URL
public void navigateToSite() throws Throwable {
System.out.println("Navigating to Website");
try {
driver.navigate().to(URL);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
You are getting some good recommendations as comments - but to answer your question directly, for an old-style ColumnFixture, which is what you have written, the method "navigateToSite" is indeed not going to be called.
These styles of fixtures are not often used anymore, Slim is preferred, and your fitnesse instance in its documentation will show you how to use Slim style. However, for a column fixture as you have written, if you want a method to be called it needs to be a "?" following name of the method in the header row.
See basic docs for column fixture:
http://fitnesse.org/FitNesse.UserGuide.FixtureGallery.BasicFitFixtures.ColumnFixture
You are mis-using column fixture, even granted the old style though. Column fixture's pattern is "here is a series of columns that represent inputs, now here is a method call I want to make to get the output and check result". Navigating a website does not often fit that pattern. In old style fitnesse it would probably be approached by an ActionFixture:
http://fitnesse.org/FitNesse.UserGuide.FixtureGallery.BasicFitFixtures.ActionFixture
In the newer Slim style, a good fit for navigation and checking where you are would be a Scenario Table.
http://www.fitnesse.org/FitNesse.UserGuide.WritingAcceptanceTests.SliM.ScenarioTable
In general doing WebDriver / Selenium tests through a wiki is worth extra thought as to whether it's your best medium. Fitnesse is really designed to be a collaborative tool for documenting and verifying business requirements, directly against source code.
Here's an example of how to do with a ColumnFixture, although again ColumnFixture not exactly appropriate:
|url|navigateToUrl?|
|www.google.com| |
java class:
public String url;
public void navigateToUrl() {
}
You could return an "OK" if it navigates alright, or return the title of the page as opposed to void if you wanted.
I have to make some operations when a Feature file starts or ends.
But I didn't find any way that Selenium can know it.
Meanwhile I use a specific hook tag to catch the beginning and another one to catch the end. But Is there a way to know it in Selenium code?
You can use before and after hook to perform some actions, you can add extra tag to your cucumber scenario and check it by scenario.getSourceTagNames(). see the example below:
#Before
public void setUpScenario(Scenario scenario) {
List<String> tags = scenario.getSourceTagNames();
if (tags.contains(scenario_specific_tag)) {
System.out.println("Before your scenario running ...." );
}
}
#After
public void endUpScenario(Scenario scenario) {
List<String> tags = scenario.getSourceTagNames();
if (tags.contains(scenario_specific_tag)) {
System.out.println("After your scenario ...." );
}
}
How to make the WebDriver wait until the page loading stops completely.
Means, it waits and checks whether entire page has been loaded or not, then only it proceeds with the next line execution.
The biggest problem is that there is no generic, one-size-fits-all solution that will work for even a majority of users. The concept of "when is my page finished loading" is rendered nearly meaningless in today's dynamic, AJAX-heavy, JavaScript-dependent web. One can wait for the browser to determine network traffic is complete, but that doesn't take JavaScript execution into account. One could define "complete" as the page's onload event having fired, but that overlooks the possibility of the page using setTimeout(). Furthermore, none of these definitions take frames or iframes into account.
When it comes to Selenium, there are a couple of factors to consider. Remember that the Selenium RC API is 10 years old. When it was designed and developed, the architecture of typical web pages made a method like waitForPageToLoad practical. The WebDriver API, on the other hand, recognizes the current reality. Individual driver implementations usually will try to wait for a page load during an explicit page navigation (e.g., driver.get()), but this wait will be a "best effort", and is not a guarantee. Please note that navigation caused by user interaction (e.g., element.click()) will be less likely to fully wait, because such interactions are asynchronous, and thus inherently have race conditions.
The correct approach for WebDriver is to wait for the element you want to interact with to appear on the subsequent page. This is best accomplished with a WebDriverWait or a similar construct. You might find some of these other constructs in the support library, mainly in those dealing with the Page Object pattern. You could also try setting the implicit wait timeout in your driver instance, but I believe using it obscures intent.
That's actually the default behavior of Selenium - it waits until all requests are complete before going on to the next line of code.
There is a design pattern provided through the Selenium support library SlowLoadableComponent that would do what you want: https://selenium.googlecode.com/svn/trunk/docs/api/java/org/openqa/selenium/support/ui/SlowLoadableComponent.html. The gist is that you write your page object to extend SlowLoadableComponent. You will have to provide implementations for two abstract methods in SlowLoadableComponent: load() and isLoaded()
TheisLoaded() method should check everything you need to consider your page 'loaded'. The load() method performs the actions necessary to load your page object. You specify a load timeout for your page object (I do this through the page object's constructor). When you invoke the get() method on your page object, which is inherited from SlowLoadableComponent, it will call isLoaded(). If your page object is not loaded, it will then call load() to load your page object. It will continue to do this until your page object is loaded or until your timeout expires.
You will have to define yourself what it means for your page object to be loaded, however. There is no out of the box way for Selenium to determine if your particular page object is loaded or not because these determinations are so context-sensitive. For example, consider a page object representing the login page for a web app. It is 'loaded' if the username and password entry text boxes and the submit login button are visible. This does not apply to a page object representing some other page in a web app. You have to custom tailor the 'is loaded' criteria for any given page object.
Here is a simple example. Basic abstract loadable object:
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.support.ui.SlowLoadableComponent;
import org.openqa.selenium.support.ui.SystemClock;
public abstract class AbstractLoadableComponent<T extends AbstractLoadableComponent<T>> extends SlowLoadableComponent<T> {
public static final int DEFAULT_TIMEOUT_IN_SECONDS = 30;
private final WebDriver driver;
private final int timeoutInSeconds;
public AbstractLoadableComponent(final WebDriver driver, final int timeoutInSeconds) {
super(new SystemClock(), timeoutInSeconds);
this.driver = driver;
this.timeoutInSeconds = timeoutInSeconds;
this.load();
}
public final WebDriver getDriver() {
return driver;
}
public final int getTimeoutInSeconds() {
return timeoutInSeconds;
}
#Override
protected void load() {
PageFactory.initElements(getDriver(), this);
}
}
Basic abstract page object:
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.ui.SlowLoadableComponent;
public abstract class AbstractPage<T extends AbstractPage<T>> extends AbstractLoadableComponent<T> {
private final String url;
public AbstractPage(final WebDriver driver) {
this(driver, driver.getCurrentUrl(), DEFAULT_TIMEOUT_IN_SECONDS);
}
public AbstractPage(final WebDriver driver, final String url) {
this(driver, url, DEFAULT_TIMEOUT_IN_SECONDS);
}
public AbstractPage(final WebDriver driver, final String url, final int timeoutInSeconds) {
super(driver, timeoutInSeconds);
this.url = url;
}
public final String getUrl() {
return url;
}
#Override
protected void load() {
super.load();
if(url != null) {
getDriver().get(url);
}
}
}
Basic concrete page object class for a login page:
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.How;
import static org.testng.Assert.assertTrue;
public final class LoginPage extends AbstractPage<LoginPage> {
#FindBy(how = How.ID, using = "username")
private WebElement usernameBox;
#FindBy(how = How.ID, using = "password")
private WebElement passwordBox;
#FindBy(how = How.NAME, using = "login")
private WebElement loginButton;
public LoginPage(final WebDriver driver) {
this(driver, driver.getCurrentUrl(), DEFAULT_TIMEOUT_IN_SECONDS);
}
public LoginPage(final WebDriver driver, final String url) {
this(driver, url, DEFAULT_TIMEOUT_IN_SECONDS);
}
public LoginPage(final WebDriver driver, final String url, final int timeoutInSeconds) {
super(driver, url, timeoutInSeconds);
}
#Override
protected final void isLoaded() throws Error {
try {
assertTrue(usernameBox.isDisplayed(), "Username text box is not displayed");
assertTrue(passwordBox.isDisplayed(), "Password text box is not displayed");
assertTrue(loginButton.isDisplayed(), "Login button is not displayed");
} catch(NoSuchElementException nsee) {
throw new Error(nsee);
}
}
}
driver.manage.implicitlywait(3, TimeUnit.Seconds) will hep.
I am using Selenium webdriver, in Java with TestNG to run an X amount of test cases.
What I would like, is for any test case to automatically restart (either from starting or from point of failure), as soon as it fails.
I know TestNG framework has the following method
#Override
public void onTestFailure(ITestResult tr) {
log("F");
}
but I do not know how to find out which testcase it was and then how would I restart it.
I wanted to see an example with actual code in it and found it here:
Restarting Test immediately with TestNg
Observe how the below tests will each be re-run once as soon as the failure happens.
import org.testng.Assert;
import org.testng.IRetryAnalyzer;
import org.testng.ITestResult;
import org.testng.annotations.Test;
public class Retry implements IRetryAnalyzer {
private int retryCount = 0;
private int maxRetryCount = 1;
public boolean retry(ITestResult result) {
if (retryCount < maxRetryCount) {
retryCount++;
return true;
}
return false;
}
#Test(retryAnalyzer = Retry.class)
public void testGenX() {
Assert.assertEquals("james", "JamesFail"); // ListenerTest fails
}
#Test(retryAnalyzer = Retry.class)
public void testGenY() {
Assert.assertEquals("hello", "World"); // ListenerTest fails
}
}
From testng.org
Every time tests fail in a suite, TestNG creates a file called testng-failed.xml in the output directory. This XML file contains the necessary information to rerun only these methods that failed, allowing you to quickly reproduce the failures without having to run the entirety of your tests.
If you want to rerun the test exactly after the failure you need to call the method that failed. You can get that method name from ITestResult object.
If you want to rerun all the failed test cases together, then you can give the testng-failed.xml as input xml after the first execution.