0

I'm trying to use asserts in selenium java. I read that for every validation, I need to use an assert as best practice.
I stumbled upon this code example:

WebElement button = wait.until(ExpectedConditions.visibilityOf(signInAndUpBtn));
Assert.assertTrue(button.isDisplayed(), "Sign In button should be visible on Home Page");

In this example, the assertion will never fail because it will fail previously on the wait. However, I want to combine the use of wait and assert, but I'm not sure what's the best way to do it.

1
  • 1
    It's not a best practice to assert something that can't possibly untrue Commented Nov 10 at 15:06

3 Answers 3

1

The assertTrue() after a wait.until() will never run if the element is not found or not visible. That’s because wait.until(...) throws a TimeoutException when the condition is not met within the given time. So the assertion becomes redundant.

But you can control the assertion output - for example, to show a clean test failure message instead of a raw timeout exception, you can catch the TimeoutException and explicitly fail the test with your own assertion message.

WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
try { 
    wait.until(ExpectedConditions.visibilityOfElementLocated(locator));
} catch (TimeoutException e) {
    Assert.fail(message + " (Element not visible after " + timeoutSeconds + "s)");
}

hope this is help :)

Sign up to request clarification or add additional context in comments.

Comments

0

The wait API is for synchronization and the predicate must pass to avoid a TimeoutException so it's not really possible to avoid a pass/fail on the predicate.

Perhaps you could wait for something else (eg wait for the spinner to disappear)

wait.until(ExpectedConditions.invisibilityOfElementLocated(By.id("spinner")));
WebElement button = driver.findElement(By.id("my-button")); // Note this may throw NoSuchElementException
Assert.assertTrue(button.isDisplayed(), "Sign in button should be visible on Home Page");

I guess if you really want to continue regardless of the exception you could do

WebElement button = null;
try {
   button = wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("my-button")));
} catch (TimeoutException e) {}
Assert.assertTrue(button != null && button.isDisplayed(), "Sign In button should be visible on Home Page");

5 Comments

That's what i thought, in my best practice the assert is really important, for both code and report readability. Doing the try catch method was the only solution i found
Ultimately you're trying to avoid throwing a TimeoutException in order to throw an AssertionException on the next line. I'm not sure I see the benefit of what you're trying to achieve
I disagree... strongly. There's no point in putting an assert in here. If the script gets past the wait, it's clearly passed. Also, wrapping all of that in a try-catch, which slows down the script, just to put in an assert to check a box is absurd.
Can you elaborate? Lets say the purpose of my test is to validate the login button display. If it fails i want the assert to fail, not the wait. It makes the code much more readable and the allure reports handles its differently
First off, a test that only validates that a functional element is displayed is mostly useless. What if the login button is displayed but doesn't work? Don't test if it's visible, make a slightly longer test that actually logs in. If successful, you've not only validated that the button is visible but also that it works by adding a fraction of a second to the run time of the test. Also, I'm not a big fan of "pretty" reports like allure, etc. I think many people end up spending a lot of time making them pretty instead of just writing more tests. Learn how to read a stack trace and you're good.
0

Perhaps you could try a WaitWrapper that returns Optional

@Slf4j
public class WaitWrapper {
   private final Wait<WebDriver> wait;

   public WaitWrapper(Wait<WebDriver> wait) { this.wait = wait }

   public <T> Optional<T> until(Function<WebDriver, T> function) {
      try {
         return Optional.of(wait.until(function));
      } catch (TimeoutException e) {
         LOG.error(e);
         return Optional.empty();
      }
   }
}

Then you could use AssertJ's Optional Support in your tests

import static org.assertj.core.api.Assertions.assertThat;
...
WaitWrapper wait = new WaitWrapper(new FluentWait<>(driver).withTimeout(...));
Optional<WebElement> buttonOption = wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("my-button"));
assertThat(buttonOption)
   .as("My fantastic button") // used in assertion failure messages
   .isPresent()
   .map(WebElement::isDisplayed).hasValue(true);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.