[Trouble Shooting 101] Element Not Visible Exception

How to Fix Element Not Visible Exception in Katalon Studio

When working with web test automation, you may encounter the following error:

selenium.ElementNotVisibleException: Element is not currently visible and so may not be interacted

This exception usually occurs when Katalon (or Selenium under the hood) attempts to interact with a web element before it becomes visible on the page. In this article, we’ll explain why this happens and how to fix it using Katalon’s built-in waiting mechanism.

What Causes Element Not Visible Exception?

This exception typically appears when:

  • The page or component is still loading
  • The element exists in the DOM but is hidden
  • The element appears only after an animation, AJAX call, or user action
  • The test script runs faster than the UI can render

Even though the object is correctly identified, Katalon cannot interact with it until it becomes visible to the user.

The Solution: Use Wait For Element Visible

To resolve this issue, you should explicitly wait for the element to become visible before interacting with it.

Katalon provides the Wait For Element Visible keyword for exactly this purpose.

Example Scenario

Let’s say you encounter the error while trying to click a Login button.

:cross_mark: Problematic Code

WebUI.openBrowser('http://demoaut.katalon.com')
WebUI.click(findTestObject('btn_Login'))

In this case, the click action may execute before the Login button is fully visible, causing the exception.

:white_check_mark: Recommended Fix

Add waitForElementVisible before interacting with the element:

WebUI.openBrowser('http://demoaut.katalon.com')
WebUI.waitForElementVisible(findTestObject('btn_Login'), 30)
WebUI.click(findTestObject('btn_Login'))

Why This Works

  • waitForElementVisible pauses the test execution
  • It waits up to 30 seconds for the element to become visible
  • Once visible, the click action executes safely

Best Practices to Avoid This Exception

  • Always wait for elements that load dynamically
  • Use explicit waits instead of relying on delays
  • Prefer waitForElementVisible over delay()
  • Ensure your Test Object locator is correct and stable

Learn More

To explore this keyword in more detail, check out the official documentation:

:blue_book: [WebUI] Wait For Element Visible

Final Thoughts

The Element Not Visible Exception is not a bug, rather it’s a signal that your test is running faster than the application UI. By adding a simple visibility check, you can make your tests more stable, reliable, and closer to real user behavior.

Happy testing! :rocket:

2 Likes

thanks for sharing this, its a good reminder

from my experience, ElementNotVisibleException usually means the element is already in the DOM, but the test tries to interact with it before it’s actually visible or clickable

a few things that often help:

  1. wait explicitly for visibility
WebUI.waitForElementVisible(findTestObject('yourObject'), 30)
WebUI.click(findTestObject('yourObject'))
  1. check for overlays or loaders
    sometimes a spinner, modal, or banner is still covering the element even though it’s present in the DOM. waiting for those to disappear can fix the issue.

  2. verify the locator
    make sure the Test Object isn’t pointing to a hidden or duplicate element. this happens a lot with dynamic pages.

  3. last resort: JS click
    if everything looks correct but WebUI.click() still fails, a JavaScript click can help but only after proper waits.

3 Likes

Thanks for sharing

Thank you for sharing!! Are we tagging these resources for quick reference’s?

1 Like

Nice documentation.

But when you say

what I, as an end user would expect is that i don’t need to explicitly add one more check in my test for WebUI.waitForElementVisible(findTestObject('btn_Login'), 30)

Ideally, Katalon should automatically wait for the element to be visible before performing the click when I use

WebUI.click(findTestObject('btn_Login')) .

To reduce this extra line of code in tests, one workaround is to create a reusable keyword and call it instead of the existing WebUI.click() method, like this

	@Keyword

	def Wait_And_Click(TestObject testObject) {

		WebUI.waitForElementPresent(testObject, 30)
//OR    WebUI.waitForElementVisible(testObject, 30)
		WebUI.enhancedClick(testObject)

	}

Then call it in the test case as:

CustomKeywords.'Common_Keywords.Wait_And_Click'(findTestObject(‘btn_Login’))

But I would really love if Katalon could implement the click() keyword in as

  • First wait for the element to be visible/present
  • Then click on it.

This will make Katalon much easier and more intuitive to use.

1 Like

@akshay_sartabe

You should use WebUI.enhancedClick instead of WebUI.click.

WebUI.enchancedClick internally always waits for the target element.

See the following source code of the WebUI.enhancedClick keyword:

package com.kms.katalon.core.webui.keyword.builtin

import java.text.MessageFormat
import java.time.Duration
import org.openqa.selenium.JavascriptExecutor
import org.openqa.selenium.WebDriver
import org.openqa.selenium.WebElement
import org.openqa.selenium.interactions.Actions
import org.openqa.selenium.support.ui.ExpectedConditions
import org.openqa.selenium.support.ui.WebDriverWait

import com.kms.katalon.core.annotation.internal.Action
import com.kms.katalon.core.configuration.RunConfiguration
import com.kms.katalon.core.exception.StepFailedException
import com.kms.katalon.core.helper.KeywordHelper
import com.kms.katalon.core.keyword.internal.SupportLevel
import com.kms.katalon.core.model.FailureHandling
import com.kms.katalon.core.testobject.TestObject
import com.kms.katalon.core.trymonad.Try
import com.kms.katalon.core.webui.common.WebUiCommonHelper
import com.kms.katalon.core.webui.constants.StringConstants
import com.kms.katalon.core.webui.driver.DriverFactory
import com.kms.katalon.core.webui.keyword.internal.WebUIAbstractKeyword
import com.kms.katalon.core.webui.keyword.internal.WebUIKeywordMain
import groovy.transform.CompileStatic

@Action(value = "enhancedClick")
class EnhancedClickKeyword extends WebUIAbstractKeyword {

    @CompileStatic
    @Override
    public SupportLevel getSupportLevel(Object ...params) {
        return super.getSupportLevel(params)
    }

    @CompileStatic
    @Override
    public Object execute(Object ...params) {
        TestObject to = getTestObject(params[0])
        FailureHandling flowControl = (FailureHandling)(params.length > 1 && params[1] instanceof FailureHandling ? params[1] : RunConfiguration.getDefaultFailureHandling())
        click(to,flowControl)
    }

    private void scrollToElement(WebDriver webDriver, WebElement webElement) {
        try {
            Actions builder = new Actions(webDriver);
            builder.moveToElement(webElement);
            builder.build().perform();
        } catch(Exception e) {
            logger.logError(e.getMessage());
        }
        try {
            ((JavascriptExecutor) webDriver).executeScript("arguments[0].scrollIntoView(true);", webElement);
        } catch(Exception e) {
            logger.logError(e.getMessage());
        }
    }
    @CompileStatic
    public void click(TestObject to, FailureHandling flowControl) throws StepFailedException {
        WebDriver driver = DriverFactory.getWebDriver();
        int timeoutInSeconds = RunConfiguration.getElementTimeoutForWeb()
        long timeoutInMillis = RunConfiguration.getElementTimeoutForWebInMillis()

        WebUIKeywordMain.runKeywordUntilTimeout({
            boolean isSwitchIntoFrame = false
            try {
                WebUiCommonHelper.checkTestObjectParameter(to)
                isSwitchIntoFrame = WebUiCommonHelper.switchToParentFrame(driver, to)
                
                WebElement webElement = WebUIAbstractKeyword.findWebElement(driver, to, timeoutInMillis)

                logger.logDebug(MessageFormat.format(StringConstants.KW_LOG_INFO_CLICKING_ON_OBJ, to.getObjectId()))
                Try.ofFailable({
                    logger.logDebug("Trying Selenium click !");
                    webElement.click();
                    return Boolean.TRUE;
                }).orElseTry({
                    logger.logDebug("Trying to scroll to the element, wait for it to be clickable and use Selenium click !");
                    scrollToElement(driver, webElement);
                    WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(timeoutInSeconds));
                    webElement = wait.until(ExpectedConditions.elementToBeClickable(webElement));
                    webElement.click();
                    return Boolean.TRUE;
                }).orElseTry({
                    logger.logDebug("Trying Javascript click !");
                    JavascriptExecutor executor = (JavascriptExecutor) driver;
                    executor.executeScript("arguments[0].click();", webElement);
                    return Boolean.TRUE;
                }).onSuccess({
                    logger.logPassed(MessageFormat.format(StringConstants.KW_LOG_PASSED_OBJ_CLICKED, to.getObjectId()))
                }).get();
            } finally {
                if (isSwitchIntoFrame) {
                    WebUiCommonHelper.switchToDefaultContent(driver)
                }
            }
        }, flowControl, RunConfiguration.getTakeScreenshotOption(), (to != null) ? MessageFormat.format(StringConstants.KW_MSG_CANNOT_CLICK_ON_OBJ_X, to.getObjectId())
        : StringConstants.KW_MSG_CANNOT_CLICK_ON_OBJ)
    }
}

Especially, please find the statement:

    ...
    @CompileStatic
    public void click(TestObject to, FailureHandling flowControl) throws StepFailedException {
        ...
                // built-in wait here!
                WebElement webElement = WebUIAbstractKeyword.findWebElement(driver, to, timeoutInMillis)

As you see in the source, the keyword always waits for the target element to be present in the DOM of the page. In most cases, this wait strategy works.

Please note the keyword does not check the visiblility and clickability of the target element. So the WebUI.enhancedClick might not work well in some edge cases.


I think that the problem of WebUI.enhancedClick keyword is its poor documentation. The doc writes:

Click on the given element using various trial-and-error methods.

Well, how poor the doc is! It explains nothing. Nobody would trust it unless appropriately documented.

2 Likes

Thanks for the detailed explanation @kazurayam .

I guess you are correct. The poor documentation does not give trust to use keyword. Also the documentation states enhancedClick() may have same effects as click().

I want to understand if at all this would any way impact the testing workflow (may be an edge case).

???

If you are asking me something, then I would just reply “PLS read the source code”.

1 Like

Given the detailed explanation by @kazurayam , now I think that the better recommended fix for such scenarios provided by @nghi.phan

would be simply to use the enhancedClick() keyword instead of adding waitForElementVisible().

I’m I correct here? Or missing some cases here?

Why would you want users to add extra lines of codes when Katalon has already done it for us?

1 Like

Perhaps she too doesn’t trust the keyword.

2 Likes

Good question @akshay_sartabe! After looking at the actual source code, here’s when each approach makes sense:

Use enhancedClick() when:

  • You just want to click an element and let Katalon handle the waiting automatically

  • The global timeout setting (in Project Settings) works for your scenario

  • You want the built-in retry logic (tries regular click → scroll + wait for clickable → JavaScript click)

Use waitForElementVisible() when:

1. You need a custom timeout different from the global setting:

// This button might take longer than usual
WebUI.waitForElementVisible(findTestObject('slow_loading_btn'), 60) // 60 seconds
WebUI.click(findTestObject('slow_loading_btn'))

Looking at the source code, enhancedClick() uses RunConfiguration.getElementTimeoutForWeb() - you can’t specify a custom timeout per element.

2. You need to perform actions OTHER than clicking:

// Wait for element to be visible, then get its text
WebUI.waitForElementVisible(findTestObject('success_message'), 10)
String message = WebUI.getText(findTestObject('success_message'))

// Wait for dropdown to be visible, then select option
WebUI.waitForElementVisible(findTestObject('country_dropdown'), 10)
WebUI.selectOptionByValue(findTestObject('country_dropdown'), 'USA', 10)

// Wait for field to be visible, then verify its value
WebUI.waitForElementVisible(findTestObject('total_price'), 10)
WebUI.verifyElementText(findTestObject('total_price'), '$99.99')

enhancedClick() is specifically for clicking - if you need to interact differently with the element, you need an explicit wait.

3. You need the boolean result for conditional logic:

boolean isVisible = WebUI.waitForElementVisible(findTestObject('optional_element'), 5)
if (isVisible) {
    WebUI.click(findTestObject('optional_element'))
} else {
    // Take alternative path
    WebUI.click(findTestObject('default_option'))
}

4. You need it as an actual assertion: Per the Katalon documentation:

When a condition is not met, Katalon Studio returns a result (either True or False) with a warning message regardless of what failure handling settings you specified.

So if you want the test to FAIL when element isn’t visible:

boolean present = WebUI.waitForElementVisible(findTestObject('critical_element'), 30)
assert present // This will fail the test if false

5. Different wait conditions for different scenarios:

// Wait for element to exist in DOM (but maybe not visible yet)
WebUI.waitForElementPresent(findTestObject('element'), 10)

// Wait for it to become visible
WebUI.waitForElementVisible(findTestObject('element'), 10)

// Wait for it to be clickable
WebUI.waitForElementClickable(findTestObject('element'), 10)

enhancedClick() only checks if element is clickable - you might need different conditions.

For simple “wait and click” with default timeout → use enhancedClick(). When you need custom timeouts, conditional logic, different actions, or specific wait strategies → use explicit wait keywords. They serve different purposes!

1 Like