WebUI.getText() may return empty string, even if the TestObject is found and has `innerText != ''`

Runtime environment

I am on Katalon Studio 8.6.0, on a Windows 11 machine.

Thesis

For some reason, WebUI.getText() may return null/empty, even though there exist some innerText in the web element on the page…

I have this BaseScrollableSelectionStrategy that doSelect(dropdownOption) by scrolling to the last available dropdown option, and then to the dropdownOption itself, until the wait for it is complete.

This is used on a CRM autocomplete, which inserts the next “page” of dropdown options (or any other widget) on scroll past current page). Hence, last avaiable dropdown option is subject to change once we scroll to it (because the app fetches the next “page” of dropdown options after that).

its doSelect is defined to be:

public void doSelect(TestObject dropdownOption) {
	final long startTime = System.currentTimeMillis();

	ActionHandler.HandleFailableAction({
		this.waitForDropdownOption(dropdownOption);
	}, { boolean success, _ ->
		KeywordUtil.logInfo("${dropdownOption.getObjectId()} ${this.getActionStatus(success, startTime)}")
		if (!success) {
			final TestObject lastAvailableDropdownItem = new TestObject("Last available dropdown item")
				.addProperty("xpath",
					ConditionType.EQUALS,
					"//lyte-drop-box[not(contains(concat(' ', @class, ' '), ' lyteDropdownHidden '))]//lyte-drop-item[last()]");

			TimeLoggerUtil.LogAction({
				if (!WebUI.waitForElementPresent(lastAvailableDropdownItem, 2))
					return false;

				GeneralWebUIUtils.ScrollDropdownOptionIntoView(lastAvailableDropdownItem);

				return true;
			}, lastAvailableDropdownItem.getObjectId(),
			"scroll into view");
		}
	}, 15)
	GeneralWebUIUtils.ScrollDropdownOptionIntoView(dropdownOption);
	WebUI.click(dropdownOption);
}

When we GeneralWebUIUtils.ScrollDropdownOptionIntoView(), we’re doing:

public static void ScrollDropdownOptionIntoView(TestObject to) {
	WebUI.executeJavaScript("arguments[0].scrollIntoView({block: 'center'})", [WebUiCommonHelper.findWebElement(to, 3)]);

	WebUI.waitForElementNotPresent(to, 1, FailureHandling.OPTIONAL);
	WebUI.waitForElementVisible(to, 2);
}

The issue

When I run a test suite full of test cases that deal with these kind of autocomplete dropdown options (and use this BaseScrollableSelectionStrategy to handle them), it runs out the entire 15+ seconds of time passed to ActionHandler.HandleFailableAction()!

The onAction (first) callback fails the whole time! It ends up calling the following general WebUI util method:

public static boolean WaitForElementTextMatches(TestObject to, String expectedText, int timeOut, FailureHandling failureHandling = FailureHandling.STOP_ON_FAILURE) {
	return this.WaitForElementCondition({ TestObject testObj ->
		String testObjectText = WebUI.getText(testObj);
		
		return testObjectText.equals(expectedText);
	}, { boolean success, TestObject testObj ->
		if (success)
			return;

		if (WebUI.waitForElementNotPresent(testObj, 1, FailureHandling.OPTIONAL)) { 
			WebUI.waitForElementPresent(testObj, timeOut);
		}
		if (WebUI.verifyElementPresent(testObj, 1, FailureHandling.OPTIONAL))
			KeywordUtil.logInfo("TestObject '${testObj.getObjectId()}' is now present!")
		
		if (WebUI.waitForElementVisible(testObj, timeOut, FailureHandling.OPTIONAL))
			KeywordUtil.logInfo("TestObject '${testObj.getObjectId()}' has text '${WebUI.getText(testObj)}'")
	},
	to,
	timeOut,
	failureHandling);
}

To add insult to injury, the element may end up present, but is NEVER visible, according to Katalon/Selenium!

I see

TestObject 'Object Repository/Page_Create Member Lead - Zoho CRM/Member Lead Information Section/Member Category autocomplete/Membership dropdown option' is now present!

but NEVER

TestObject 'Object Repository/Page_Create Member Lead - Zoho CRM/Member Lead Information Section/Member Category autocomplete/Membership dropdown option' has text

HTML or GTFO

After the scroll, the dropdown list HTML looks like:

<lyte-drop-box
  class="w100per createAutocomplete alyteautocompleteDropdown undefined lyteDropdownDown lyteDropboxRightAlignToButton"
  style="position: absolute; width: 388px; min-width: 388px; top: 1703.34px; left: 251px;"
>
  <span class="lyteArrow" style="width: 388px;"></span>
  <div
    class="w100per h5 m0"
    mouseout="crm-create-fields => setFullViewRec(event,false)"
    mouseenter="crm-create-fields => setFullViewRec"
  ></div>
  <lyte-drop-body
    role="listbox"
    id="Lyte_Drop_Body_34"
    lyte-rendered-ce=""
    style="max-height: 250px; width: auto;"
    class="lyteScrollBar"
  >
    <lyte-drop-item
      data-zcqa="Member Category_4623170000074126386"
      data-value="4623170000074126386"
      aria-selected="false"
      role="option"
      id="Lyte_Drop_Item_23"
      lyte-rendered-ce=""
      class=""
    >
      <lyte-autocomplete-label aria-selected="false"
        ><span
          class="lookup-autoc-text"
          lt-prop-tooltip-class="lcreateTooltip"
          lt-prop-tooltip-config='{"position" : "followcursor","margin" : "10","hidedelay" : "50"}'
          mouseenter="crm-create-fields => setLookupTooltip"
          >Child Membership - Option B </span
        ><i
          id="4623170000074126386"
          class="info_icon infoIcoLookupAuto cP fR vh"
          mouseout="crm-create-fields => infoPop(this,val,event)"
          mouseenter="crm-create-fields => infoPop"
          ><crmutil-icon
            icon-name="info-solid"
            icon-class="zcicn-info-solid crmBaseIcon"
            lyte-rendered=""
          >
            <svg class="zcicn_embedSvg zcicn-info-solid crmBaseIcon">
              <use href="#zcicn-info-solid"></use>
            </svg> </crmutil-icon
        ></i>
      </lyte-autocomplete-label>
    </lyte-drop-item>
    <lyte-drop-item
      data-zcqa="Member Category_4623170000074124524"
      data-value="4623170000074124524"
      aria-selected="false"
      role="option"
      id="Lyte_Drop_Item_24"
      lyte-rendered-ce=""
    >
      <lyte-autocomplete-label aria-selected="false"
        ><span
          class="lookup-autoc-text"
          lt-prop-tooltip-class="lcreateTooltip"
          lt-prop-tooltip-config='{"position" : "followcursor","margin" : "10","hidedelay" : "50"}'
          mouseenter="crm-create-fields => setLookupTooltip"
          >Child Membership - Option D </span
        ><i
          id="4623170000074124524"
          class="info_icon infoIcoLookupAuto cP fR vh"
          mouseout="crm-create-fields => infoPop(this,val,event)"
          mouseenter="crm-create-fields => infoPop"
          ><crmutil-icon
            icon-name="info-solid"
            icon-class="zcicn-info-solid crmBaseIcon"
            lyte-rendered=""
          >
            <svg class="zcicn_embedSvg zcicn-info-solid crmBaseIcon">
              <use href="#zcicn-info-solid"></use>
            </svg> </crmutil-icon
        ></i>
      </lyte-autocomplete-label>
    </lyte-drop-item>
    <lyte-drop-item
      data-zcqa="Member Category_4623170000074067550"
      data-value="4623170000074067550"
      aria-selected="false"
      role="option"
      id="Lyte_Drop_Item_25"
      lyte-rendered-ce=""
    >
      <lyte-autocomplete-label aria-selected="false"
        ><span
          class="lookup-autoc-text"
          lt-prop-tooltip-class="lcreateTooltip"
          lt-prop-tooltip-config='{"position" : "followcursor","margin" : "10","hidedelay" : "50"}'
          mouseenter="crm-create-fields => setLookupTooltip"
          >Child Membership - Option A </span
        ><i
          id="4623170000074067550"
          class="info_icon infoIcoLookupAuto cP fR vh"
          mouseout="crm-create-fields => infoPop(this,val,event)"
          mouseenter="crm-create-fields => infoPop"
          ><crmutil-icon
            icon-name="info-solid"
            icon-class="zcicn-info-solid crmBaseIcon"
            lyte-rendered=""
          >
            <svg class="zcicn_embedSvg zcicn-info-solid crmBaseIcon">
              <use href="#zcicn-info-solid"></use>
            </svg> </crmutil-icon
        ></i>
      </lyte-autocomplete-label>
    </lyte-drop-item>
    <lyte-drop-item
      data-zcqa="Member Category_4623170000056764203"
      data-value="4623170000056764203"
      aria-selected="false"
      role="option"
      id="Lyte_Drop_Item_26"
      lyte-rendered-ce=""
    >
      <lyte-autocomplete-label aria-selected="false"
        ><span
          class="lookup-autoc-text"
          lt-prop-tooltip-class="lcreateTooltip"
          lt-prop-tooltip-config='{"position" : "followcursor","margin" : "10","hidedelay" : "50"}'
          mouseenter="crm-create-fields => setLookupTooltip"
          >Membership - Option F </span
        ><i
          id="4623170000056764203"
          class="info_icon infoIcoLookupAuto cP fR vh"
          mouseout="crm-create-fields => infoPop(this,val,event)"
          mouseenter="crm-create-fields => infoPop"
          ><crmutil-icon
            icon-name="info-solid"
            icon-class="zcicn-info-solid crmBaseIcon"
            lyte-rendered=""
          >
            <svg class="zcicn_embedSvg zcicn-info-solid crmBaseIcon">
              <use href="#zcicn-info-solid"></use>
            </svg> </crmutil-icon
        ></i>
      </lyte-autocomplete-label>
    </lyte-drop-item>
    <lyte-drop-item
      data-zcqa="Member Category_4623170000056748147"
      data-value="4623170000056748147"
      aria-selected="false"
      role="option"
      id="Lyte_Drop_Item_27"
      lyte-rendered-ce=""
    >
      <lyte-autocomplete-label aria-selected="false"
        ><span
          class="lookup-autoc-text"
          lt-prop-tooltip-class="lcreateTooltip"
          lt-prop-tooltip-config='{"position" : "followcursor","margin" : "10","hidedelay" : "50"}'
          mouseenter="crm-create-fields => setLookupTooltip"
          >Membership - Option G </span
        ><i
          id="4623170000056748147"
          class="info_icon infoIcoLookupAuto cP fR vh"
          mouseout="crm-create-fields => infoPop(this,val,event)"
          mouseenter="crm-create-fields => infoPop"
          ><crmutil-icon
            icon-name="info-solid"
            icon-class="zcicn-info-solid crmBaseIcon"
            lyte-rendered=""
          >
            <svg class="zcicn_embedSvg zcicn-info-solid crmBaseIcon">
              <use href="#zcicn-info-solid"></use>
            </svg> </crmutil-icon
        ></i>
      </lyte-autocomplete-label>
    </lyte-drop-item>
    <lyte-drop-item
      data-zcqa="Member Category_4623170000035961028"
      data-value="4623170000035961028"
      aria-selected="false"
      role="option"
      id="Lyte_Drop_Item_28"
      lyte-rendered-ce=""
    >
      <lyte-autocomplete-label aria-selected="false"
        ><span
          class="lookup-autoc-text"
          lt-prop-tooltip-class="lcreateTooltip"
          lt-prop-tooltip-config='{"position" : "followcursor","margin" : "10","hidedelay" : "50"}'
          mouseenter="crm-create-fields => setLookupTooltip"
          >Membership - Option E </span
        ><i
          id="4623170000035961028"
          class="info_icon infoIcoLookupAuto cP fR vh"
          mouseout="crm-create-fields => infoPop(this,val,event)"
          mouseenter="crm-create-fields => infoPop"
          ><crmutil-icon
            icon-name="info-solid"
            icon-class="zcicn-info-solid crmBaseIcon"
            lyte-rendered=""
          >
            <svg class="zcicn_embedSvg zcicn-info-solid crmBaseIcon">
              <use href="#zcicn-info-solid"></use>
            </svg> </crmutil-icon
        ></i>
      </lyte-autocomplete-label>
    </lyte-drop-item>
    <lyte-drop-item
      data-zcqa="Member Category_4623170000035914031"
      data-value="4623170000035914031"
      aria-selected="false"
      role="option"
      id="Lyte_Drop_Item_29"
      lyte-rendered-ce=""
    >
      <lyte-autocomplete-label aria-selected="false"
        ><span
          class="lookup-autoc-text"
          lt-prop-tooltip-class="lcreateTooltip"
          lt-prop-tooltip-config='{"position" : "followcursor","margin" : "10","hidedelay" : "50"}'
          mouseenter="crm-create-fields => setLookupTooltip"
          >Membership - Option C </span
        ><i
          id="4623170000035914031"
          class="info_icon infoIcoLookupAuto cP fR vh"
          mouseout="crm-create-fields => infoPop(this,val,event)"
          mouseenter="crm-create-fields => infoPop"
          ><crmutil-icon
            icon-name="info-solid"
            icon-class="zcicn-info-solid crmBaseIcon"
            lyte-rendered=""
          >
            <svg class="zcicn_embedSvg zcicn-info-solid crmBaseIcon">
              <use href="#zcicn-info-solid"></use>
            </svg> </crmutil-icon
        ></i>
      </lyte-autocomplete-label>
    </lyte-drop-item>
    <lyte-drop-item
      data-zcqa="Member Category_4623170000035905010"
      data-value="4623170000035905010"
      aria-selected="false"
      role="option"
      id="Lyte_Drop_Item_30"
      lyte-rendered-ce=""
    >
      <lyte-autocomplete-label aria-selected="false"
        ><span
          class="lookup-autoc-text"
          lt-prop-tooltip-class="lcreateTooltip"
          lt-prop-tooltip-config='{"position" : "followcursor","margin" : "10","hidedelay" : "50"}'
          mouseenter="crm-create-fields => setLookupTooltip"
          >Membership - Option D </span
        ><i
          id="4623170000035905010"
          class="info_icon infoIcoLookupAuto cP fR vh"
          mouseout="crm-create-fields => infoPop(this,val,event)"
          mouseenter="crm-create-fields => infoPop"
          ><crmutil-icon
            icon-name="info-solid"
            icon-class="zcicn-info-solid crmBaseIcon"
            lyte-rendered=""
          >
            <svg class="zcicn_embedSvg zcicn-info-solid crmBaseIcon">
              <use href="#zcicn-info-solid"></use>
            </svg> </crmutil-icon
        ></i>
      </lyte-autocomplete-label>
    </lyte-drop-item>
    <lyte-drop-item
      data-zcqa="Member Category_4623170000035889035"
      data-value="4623170000035889035"
      aria-selected="false"
      role="option"
      id="Lyte_Drop_Item_31"
      lyte-rendered-ce=""
    >
      <lyte-autocomplete-label aria-selected="false"
        ><span
          class="lookup-autoc-text"
          lt-prop-tooltip-class="lcreateTooltip"
          lt-prop-tooltip-config='{"position" : "followcursor","margin" : "10","hidedelay" : "50"}'
          mouseenter="crm-create-fields => setLookupTooltip"
          >Membership - Option B </span
        ><i
          id="4623170000035889035"
          class="info_icon infoIcoLookupAuto cP fR vh"
          mouseout="crm-create-fields => infoPop(this,val,event)"
          mouseenter="crm-create-fields => infoPop"
          ><crmutil-icon
            icon-name="info-solid"
            icon-class="zcicn-info-solid crmBaseIcon"
            lyte-rendered=""
          >
            <svg class="zcicn_embedSvg zcicn-info-solid crmBaseIcon">
              <use href="#zcicn-info-solid"></use>
            </svg> </crmutil-icon
        ></i>
      </lyte-autocomplete-label>
    </lyte-drop-item>
    <lyte-drop-item
      data-zcqa="Member Category_4623170000035827103"
      data-value="4623170000035827103"
      aria-selected="false"
      role="option"
      id="Lyte_Drop_Item_32"
      lyte-rendered-ce=""
    >
      <lyte-autocomplete-label aria-selected="false"
        ><span
          class="lookup-autoc-text"
          lt-prop-tooltip-class="lcreateTooltip"
          lt-prop-tooltip-config='{"position" : "followcursor","margin" : "10","hidedelay" : "50"}'
          mouseenter="crm-create-fields => setLookupTooltip"
          >Membership - Option A </span
        ><i
          id="4623170000035827103"
          class="info_icon infoIcoLookupAuto cP fR vh"
          mouseout="crm-create-fields => infoPop(this,val,event)"
          mouseenter="crm-create-fields => infoPop"
          ><crmutil-icon
            icon-name="info-solid"
            icon-class="zcicn-info-solid crmBaseIcon"
            lyte-rendered=""
          >
            <svg class="zcicn_embedSvg zcicn-info-solid crmBaseIcon">
              <use href="#zcicn-info-solid"></use>
            </svg> </crmutil-icon
        ></i>
      </lyte-autocomplete-label>
    </lyte-drop-item>
    <lyte-drop-item
      data-zcqa="Member Category_4623170000026970010"
      data-value="4623170000026970010"
      aria-selected="false"
      role="option"
      id="Lyte_Drop_Item_33"
      lyte-rendered-ce=""
    >
      <lyte-autocomplete-label aria-selected="false"
        ><span
          class="lookup-autoc-text"
          lt-prop-tooltip-class="lcreateTooltip"
          lt-prop-tooltip-config='{"position" : "followcursor","margin" : "10","hidedelay" : "50"}'
          mouseenter="crm-create-fields => setLookupTooltip"
          >Corporate Membership </span
        ><i
          id="4623170000026970010"
          class="info_icon infoIcoLookupAuto cP fR vh"
          mouseout="crm-create-fields => infoPop(this,val,event)"
          mouseenter="crm-create-fields => infoPop"
          ><crmutil-icon
            icon-name="info-solid"
            icon-class="zcicn-info-solid crmBaseIcon"
            lyte-rendered=""
          >
            <svg class="zcicn_embedSvg zcicn-info-solid crmBaseIcon">
              <use href="#zcicn-info-solid"></use>
            </svg> </crmutil-icon
        ></i>
      </lyte-autocomplete-label>
    </lyte-drop-item>
    <lyte-drop-item
      data-zcqa="Member Category_4623170000014601011"
      data-value="4623170000014601011"
      aria-selected="false"
      role="option"
      id="Lyte_Drop_Item_35"
      lyte-rendered-ce=""
    >
      <lyte-autocomplete-label aria-selected="false"
        ><span
          class="lookup-autoc-text"
          lt-prop-tooltip-class="lcreateTooltip"
          lt-prop-tooltip-config='{"position" : "followcursor","margin" : "10","hidedelay" : "50"}'
          mouseenter="crm-create-fields => setLookupTooltip"
          >Child Membership </span
        ><i
          id="4623170000014601011"
          class="info_icon infoIcoLookupAuto cP fR vh"
          mouseout="crm-create-fields => infoPop(this,val,event)"
          mouseenter="crm-create-fields => infoPop"
          ><crmutil-icon
            icon-name="info-solid"
            icon-class="zcicn-info-solid crmBaseIcon"
            lyte-rendered=""
          >
            <svg class="zcicn_embedSvg zcicn-info-solid crmBaseIcon">
              <use href="#zcicn-info-solid"></use>
            </svg> </crmutil-icon
        ></i>
      </lyte-autocomplete-label>
    </lyte-drop-item>
    <lyte-drop-item
      data-zcqa="Member Category_4623170000014583083"
      data-value="4623170000014583083"
      aria-selected="false"
      role="option"
      id="Lyte_Drop_Item_36"
      lyte-rendered-ce=""
    >
      <lyte-autocomplete-label aria-selected="false"
        ><span
          class="lookup-autoc-text"
          lt-prop-tooltip-class="lcreateTooltip"
          lt-prop-tooltip-config='{"position" : "followcursor","margin" : "10","hidedelay" : "50"}'
          mouseenter="crm-create-fields => setLookupTooltip"
          >Standard Membership </span
        ><i
          id="4623170000014583083"
          class="info_icon infoIcoLookupAuto cP fR vh"
          mouseout="crm-create-fields => infoPop(this,val,event)"
          mouseenter="crm-create-fields => infoPop"
          ><crmutil-icon
            icon-name="info-solid"
            icon-class="zcicn-info-solid crmBaseIcon"
            lyte-rendered=""
          >
            <svg class="zcicn_embedSvg zcicn-info-solid crmBaseIcon">
              <use href="#zcicn-info-solid"></use>
            </svg> </crmutil-icon
        ></i>
      </lyte-autocomplete-label>
    </lyte-drop-item>
    <lyte-drop-item
      data-zcqa="Member Category_4623170000014576015"
      data-value="4623170000014576015"
      aria-selected="false"
      role="option"
      id="Lyte_Drop_Item_37"
      lyte-rendered-ce=""
    >
      <lyte-autocomplete-label aria-selected="false"
        ><span
          class="lookup-autoc-text"
          lt-prop-tooltip-class="lcreateTooltip"
          lt-prop-tooltip-config='{"position" : "followcursor","margin" : "10","hidedelay" : "50"}'
          mouseenter="crm-create-fields => setLookupTooltip"
          >Gold Membership </span
        ><i
          id="4623170000014576015"
          class="info_icon infoIcoLookupAuto cP fR vh"
          mouseout="crm-create-fields => infoPop(this,val,event)"
          mouseenter="crm-create-fields => infoPop"
          ><crmutil-icon
            icon-name="info-solid"
            icon-class="zcicn-info-solid crmBaseIcon"
            lyte-rendered=""
          >
            <svg class="zcicn_embedSvg zcicn-info-solid crmBaseIcon">
              <use href="#zcicn-info-solid"></use>
            </svg> </crmutil-icon
        ></i>
      </lyte-autocomplete-label>
    </lyte-drop-item>
    <lyte-drop-item
      data-zcqa="Member Category_4623170000014557044"
      data-value="4623170000014557044"
      aria-selected="false"
      role="option"
      id="Lyte_Drop_Item_38"
      lyte-rendered-ce=""
    >
      <lyte-autocomplete-label aria-selected="false"
        ><span
          class="lookup-autoc-text"
          lt-prop-tooltip-class="lcreateTooltip"
          lt-prop-tooltip-config='{"position" : "followcursor","margin" : "10","hidedelay" : "50"}'
          mouseenter="crm-create-fields => setLookupTooltip"
          >Membership </span
        ><i
          id="4623170000014557044"
          class="info_icon infoIcoLookupAuto cP fR vh"
          mouseout="crm-create-fields => infoPop(this,val,event)"
          mouseenter="crm-create-fields => infoPop"
          ><crmutil-icon
            icon-name="info-solid"
            icon-class="zcicn-info-solid crmBaseIcon"
            lyte-rendered=""
          >
            <svg class="zcicn_embedSvg zcicn-info-solid crmBaseIcon">
              <use href="#zcicn-info-solid"></use>
            </svg> </crmutil-icon
        ></i>
      </lyte-autocomplete-label>
    </lyte-drop-item>
    <lyte-drop-item
      data-zcqa="Member Category_4623170000014541068"
      data-value="4623170000014541068"
      aria-selected="false"
      role="option"
      id="Lyte_Drop_Item_39"
      lyte-rendered-ce=""
    >
      <lyte-autocomplete-label aria-selected="false"
        ><span
          class="lookup-autoc-text"
          lt-prop-tooltip-class="lcreateTooltip"
          lt-prop-tooltip-config='{"position" : "followcursor","margin" : "10","hidedelay" : "50"}'
          mouseenter="crm-create-fields => setLookupTooltip"
          >Silver Membership </span
        ><i
          id="4623170000014541068"
          class="info_icon infoIcoLookupAuto cP fR vh"
          mouseout="crm-create-fields => infoPop(this,val,event)"
          mouseenter="crm-create-fields => infoPop"
          ><crmutil-icon
            icon-name="info-solid"
            icon-class="zcicn-info-solid crmBaseIcon"
            lyte-rendered=""
          >
            <svg class="zcicn_embedSvg zcicn-info-solid crmBaseIcon">
              <use href="#zcicn-info-solid"></use>
            </svg> </crmutil-icon
        ></i>
      </lyte-autocomplete-label>
    </lyte-drop-item>
    <div class="lyteDropdownNoResult" style="display: none;">
      No Results Found
    </div></lyte-drop-body
  >
  <span
    id="Crm_Potentials_POTENTIALCF04_load_img"
    class="lookupTxtOverflow pL20 pR20 dN"
  >
    <img
      class="mB6 dIB"
      alt="loading"
      src="//img.zohocdn.com/crm/images/loading_599c9b1_.gif"
    />
  </span>
  <div
    class="w100per h5 m0"
    mouseout="crm-create-fields => setFullViewRec(event,false)"
    mouseenter="crm-create-fields => setFullViewRec"
  ></div>
  <lyte-drop-footer>
    <div
      data-zcqa="AddNewRecord"
      class="dropFooterList alignLeft pL25"
      click="crm-create-fields => newAction()"
    >
      New Member Category
    </div>
  </lyte-drop-footer>
  <div class="lyteautocompleteError noErrClass" style="display: none;"></div>
  <div
    class="lyteScrollContainer lyteScrollContainerY"
    style="visibility: hidden;"
  >
    <div
      class="lyteScrollDiv"
      style="height: 161.392px; transform: translateY(93.6076px);"
    ></div>
  </div>
  <div
    class="lyteScrollContainer lyteScrollContainerX"
    style="visibility: hidden;"
  >
    <div class="lyteScrollDiv"></div></div
></lyte-drop-box>

Before the scroll, the dropdown list contains up to the Corporate Membership dropdown item.
After the scroll, we see the Corporate Membership dropdown item in the viewport, and the whole list is available.

What have I tried about this problem

I modified my onCheckCondition (first) callback inside the util method, to get the text via JavaScript if WebUI.getText(to) is null or ''. Here’s what the method looks like now:

public static boolean WaitForElementTextMatches(TestObject to, String expectedText, int timeOut, FailureHandling failureHandling = FailureHandling.STOP_ON_FAILURE) {
	return this.WaitForElementCondition({ TestObject testObj ->
		String testObjectText = WebUI.getText(testObj);
		if (SMDStringUtils.IsNullOrEmpty(testObjectText))
			testObjectText = (String)WebUI.executeJavaScript('return arguments[0].innerText', [WebUiCommonHelper.findWebElement(testObj, 1)]);  
		
		return testObjectText.equals(expectedText);
	}, { boolean success, TestObject testObj ->
		if (success)
			return;

		if (WebUI.waitForElementNotPresent(testObj, 1, FailureHandling.OPTIONAL)) { 
			WebUI.waitForElementPresent(testObj, timeOut);
		}
		
		if (WebUI.waitForElementVisible(testObj, timeOut, FailureHandling.OPTIONAL))
			KeywordUtil.logInfo("TestObject '${testObj.getObjectId()}' has text '${WebUI.getText(testObj)}'")
	},
	to,
	timeOut,
	failureHandling);
}

I run it, and the hanging problem goes away! I don’t even have to change up anything else!!

OK, but what’s the problem, Mike?!

The problem is that WebUI.getText(testObject), and the element.getText() that happens behind the scene, may return some empty string, despite the HTML element may be in the DOM, already waited on by the testing code, it has some innerText, and the test may have found it.

What causes this to happen?!

Why are you surprised that a web standard dom interface (accessed via JavaScript live in the browser) works?

Didn’t you say that was a code smell a while back? Or was that something else?

Relax. I’m teasing you.

I’m obviously not going to dig into your code to analyze this in anything like the depth it requires. Sorry.

But seriously, There’s a reason I use very little of WebUI – all of my interaction code (clicks etc) is pure JS. With your coding knowledge, I’m surprised you’re not writing your own primitives (like I do). It’s the only sure-fire way to reason about your code.

Tagging members from our Studio Product Team for further support: @Jass @uyen.do

it is now 2026, and this still hasn’t been fixed. I can’t use “getText()” to get the “innerText” value as the method documentation suggests. If on the other hand, I use “getAttribute(‘innerText’)” I do get a value.

Is this going to be fixed. Or an explanation of why “getText()” is not returning the value as stated?

This returns null/empty

	String date = WebUI.getText(findTestObject('my_obj'))

This returns a value “01/01/2001”

	String date = WebUI.getAttribute(findTestObject('my_obj'), 'innerText')

let me loop our PM to this thread @xuan.tran, can you take a look please

If you consider <innerText> to be an attribute where your information is stored, then wouldn’t it make sense to use “getAttribute” to get access to that tidbit. “getText” is used to get the label text or static text, like a <p> or such.

This is a known and expected behavior in Katalon (and Selenium underneath), not really a “bug” that needs fixing.

Why WebUI.getText() returns empty but getAttribute('innerText') works

Short answer

WebUI.getText() does NOT directly read innerText.
It returns only the visible rendered text as determined by Selenium’s WebElement.getText() rules.

getAttribute('innerText'), on the other hand, directly reads the DOM property, so it can return text even when Selenium considers the element’s text non-visible.

What actually happens under the hood

:one: WebUI.getText() behavior

WebUI.getText() is a wrapper over Selenium’s:
WebElement,getText()

Selenium returns text only when ALL of the following are true:

  • The element is visible

  • The text is rendered

  • The text is not hidden by CSS

  • The element is not an input-type element

  • The text is not dynamically injected after render without reflow

  • The element does not use ::before, ::after, shadow DOM, etc.

If any one condition fails, Selenium returns:
”” (empty string)

:white_check_mark: This is by design, not a Katalon bug.

Why getAttribute('innerText') works

WebUI.getAttribute(testobj,’innerText’)

Reads the DOM property directly

  • Ignores visibility rules

  • Returns whatever the browser holds in memory

That’s why it works even when:

  • Element is hidden

  • Text is dynamically updated

  • Text is inside spans/divs with CSS tricks

  • Element is off-screen

This is not a bug, it the expected behaviour

Please show the HTML source code on browser.
Without looking at the HTML, nobody would understand your issue.

@mark.bain3

<span class="ng-star-inserted">

The class value ng-* implies that this HTML was generated by Angular. Possibly the HTML element you want is dynamically managed by Angular. JavaScript-driven HTML is sensitive for timing issues. Selenium-based testing tools including Katalon Studio is not very good at testing JavaScript-driver HTMLs. Your selenium-based test script must make sure that the HTML is already present and visible before the script tries to get access its “innerText”. You have to insert WebUI.waitForElementVisible or other keyword just before the line of WebUI.getText(). Otherwise, WebUI.getText() may return empty string even if you surely expect that the TestObject to be there. Yes, the HTML element may be found a few seconds after your call WebUI.getText(), but the element was not actually there yet at the very instant when WebUI.getText() was called.

Selenium-based testing tools including Katalon Studio requires every users to be responsible for inserting appropriate calls to “wait for element to be present and visible” before trying to get the content text. You must not forget it.

On the other hand, Playwright and Puppeteer do waiting automatically.

Playwright would be better for those who work on the system based on JavaScript-driven apps such as Angular, React and Vue.