0

So I had it working earlier but I messed up something in my code and now the FluentWait method doesnt seem to call properly. If I run it using quickRun set to false it works as intended (because of the implicit) but when I set it to true it doesnt as it will not wait for the elements to load correctly. Does anyone know exactly what I did wrong?

package myPackage;

import java.util.concurrent.TimeUnit;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.safari.SafariDriver;
import org.openqa.selenium.support.ui.FluentWait;
import org.openqa.selenium.support.ui.Wait;
import com.google.common.base.Function;

//import com.gargoylesoftware.htmlunit.javascript.host.Console;
//https://www.codeproject.com/articles/143430/test-your-web-application-s-ui-with-junit-and-sele

//this will open a dynamic page example (ie. youtube) trending
public class youtubeTest {

  public boolean quickRun = false; //Disable for debugging otherwise full speed
  private static int defaultDebugDelay = 2; //Time in sec for next test to occur in debug 

  //do no change any of the below
  private String testUrl; //target url destination ie youtube
  private WebDriver driver; //webdriver instance to reference within class
  private int testIndex = 1; //initial index value for console outputting

  public WebElement fluentWait(final By locator) {
    Wait < WebDriver > wait = new FluentWait < WebDriver > (driver)
      .withTimeout(30, TimeUnit.SECONDS)
      .pollingEvery(1, TimeUnit.SECONDS)
      .ignoring(NoSuchElementException.class);

    WebElement foo = wait.until(new Function < WebDriver, WebElement > () {
      public WebElement apply(WebDriver driver) {
        return driver.findElement(locator);
      }
    });

    return foo;
  };

  @
  Before
  public void beforeTest() {
    driver = new SafariDriver();
    System.out.println("Setting up Test...");
    if (quickRun) {
      System.out.println("Test Type: Quick Run (Fastest Mode)");
    } else {
      System.out.println("Test Type: Slow Run (Debug Mode) - Each Test has a " + defaultDebugDelay + " sec call time buffer");
    }
    testUrl = "https://www.youtube.com";
    driver.get(testUrl);
    System.out.println("Setting Driver " + driver + "for url: " + testUrl);

  }

  @
  Test
  public void Test() {
    //insert unit tests within here
    //open yt nav menu
    locateClickableElement("#appbar-guide-button");
    //go to trending
    locateClickableElement("#trending-guide-item");
    //click on 4th Trending video from list
    //locateClickableElement(".expanded-shelf-content-item-wrapper", 3);
    locateClickableElement(".expanded-shelf-content-item-wrapper");


  }

  @
  After
  public void afterTest() throws Exception {
    //wait 10 sec before closing test indefinitely
    System.out.println("Test auto ending in 10 seconds...");
    Thread.sleep(10000);
    stopTest();
  }

  //individual unit tests
  private void locateClickableElement(String ExpectedElement, int child) {
    //format string into something like: "ELEMENT:nth-child(1)"
    String formattedString = ExpectedElement + ":nth-child(" + child + ")";
    System.out.println("Strung: " + formattedString);
    locateClickableElement(formattedString);
  }

  private void locateClickableElement(String ExpectedElement) {
    try {
      System.out.println("Test " + testIndex + ": locateClickableElement(" + ExpectedElement + ")");

      //do absolute delay for visual debugging
      if (!quickRun) Thread.sleep(2000);

      //click on target if found
      fluentWait(By.cssSelector(ExpectedElement)).click();
      System.out.println("Test " + testIndex + ": Successful Click on Element(" + ExpectedElement + ")");

    } catch (Exception e) {
      //whenever error is found output it and end program
      System.out.println("Error Could not locateClickableElement(" + ExpectedElement + ")");
      System.out.println("Exception Handled:" + e.getMessage());
      stopTest("error");
    }
    testIndex++;
  }

  private void stopTest() {
    System.out.println("Test Completed: Reached End.");
    driver.quit();
  }

  private void stopTest(String typeError) {
    System.out.println("Test Completed: With an Error.");
    driver.quit();
  }

}
Potion
  • 785
  • 1
  • 14
  • 36

1 Answers1

0

I would write this a different way and offer some advice.

  1. Don't slow your test down using "debug mode". If you want to debug your test, use breakpoints and step through the code to see how it's working.

  2. You don't need FluentWait here. A simple WebDriverWait using ExpectedConditions.elementToBeClickable(locator) will work just fine and is less complicated. You shouldn't even need it, if you accept my changes.

  3. Don't pass locators using String, use the intended locator class, By. You won't have to interpret it, translate it, etc. and it will be faster and more flexible.

  4. Unless you are trying to test the UI (which I'm assuming you don't work for youtube), then you can just navigate to the Trending page using the Trending link at the top of the page. It will save you time and clicks. If you aren't testing it, don't test it... get to where you are going as fast as possible. You don't want your test failing due to UI you aren't trying to test and you always want your tests to go as fast as possible. (NOTE: You could even navigate directly to the trending URL.)

  5. You don't need the locateClickableElement() functions. Just click the links... it should be a one liner. If there's an error, it will be obvious. You don't need to print, "There was an error." after an exception message was printed.

  6. You don't need the stopTest() functions... just stop the test. When the browser closes, it will be obvious the test is complete.

The rewritten code is below. It's nice and simple (and short) and should be faster.

public class youtubeTest
{
    // do no change any of the below
    private String testUrl = "https://www.youtube.com"; // target url destination ie youtube
    private WebDriver driver; // webdriver instance to reference within class

    private By trendingGuideLinkLocator = By.cssSelector("#trending-guide-item");
    private By trendingLinkLocator = By.xpath("//h2[contains(.,'Trending')]");

    @Before
    public void beforeTest()
    {
        System.out.println("Setting up Test..."); // if you are going to have this statement, put it at the start of beforeTest()
        driver = new SafariDriver();
        driver.get(testUrl);
        System.out.println("Set Driver " + driver + "for url: " + testUrl);
    }

    @Test
    public void Test()
    {
        // insert unit tests within here
        driver.findElement(trendingLinkLocator).click(); // just click the Trending link, it's faster
        driver.findElements(trendingGuideLinkLocator).get(3).click();
    }

    @After
    public void afterTest()
    {
        driver.close();
        driver.quit();
    }
}

If you don't want to change all this, the simple answer to your question is replace FluentWait with WebDriverWait.

fluentWait(By.cssSelector(ExpectedElement)).click();

would be replaced by

new WebDriverWait(driver, 10).until(ExpectedConditions.elementToBeClickable(trendingLinkLocator)).click();
JeffC
  • 22,180
  • 5
  • 32
  • 55
  • Wow this really helped me understand so much. I should remember to keep things simple. 1) Good idea.. i was overthinking it, ill make sure to do that. 2) When would I need to use fluentwait? When the loading time is highly unpredictable? 3) Ill make sure to just do that directly and declare them as you did in your exmaple 4) I am testing UI for our software. Its mainly UI navigation. Its a customized RocketChat App. So each Class is a Unit test for each module? Would I navigate to the link or would I reference with a public static driver? Ill apply all this to the code I worked on today – Potion Dec 13 '16 at 08:52
  • `FluentWait` is for when you need a custom wait... something that isn't covered by `ExpectedConditions`. I would suggest that you read some Java Unit Test best practices articles. I don't do a lot of unit testing. – JeffC Dec 13 '16 at 13:56
  • I will definitely go into more articles. Its a little rush since this assignment was thrown at me with little to no knowledge about the testing process or scheme. Thanks for helping out – Potion Dec 13 '16 at 22:46
  • Thank you I learned a lot since this post. One problem I always wondered... When I try to debug, why does it not resume? It will run `@BeforeClass` but go to the end then not jump to the `@Before` and `@Tests` using JUnit in debug more? Also using any sort of wait does not work with debugger. How would I debug in these cases? @JeffC – Potion Dec 21 '16 at 19:30
  • When I debug, I usually put a breakpoint on or near the line that is causing the issue so I can see how the variables are set up, what state the page(s) are in, etc. going into the error. How to create breakpoints will depend on the IDE you use. You will have to look for and read the documentation for your IDE. – JeffC Dec 22 '16 at 03:34
  • I use eclipse. I know how to debug with it but it doesnt seem to work when debugging selenium Wait calls, is that normal? – Potion Dec 27 '16 at 18:41