Variable not receiving value from javascript

“undefined” is not being returned. We were able to output the value returned from the javascript and it is the correct value, which is “18”.

It is, Jeff, trust me. That’s how JavaScript works.

There is only one way I can think of for your forEach to be behaving differently: your “developer” has hijacked (overwritten) the Array.forEach prototype. Doubtful.

Try this. And before you run this code, be sure you understand what YOU are saying compared to what I am saying. This code backs up what I am saying but runs counter to what you are saying.

    String js = '''
      [1,2,3,4,5].forEach(function(n) {
        if(n === 3) {
          return n;  // WILL NOT WORK
        }
      });
    '''
    int n = WebUI.executeJavaScript(js, null)
    println "result: " + n

That should fail with an error complaining about casting null to an int – and rightly so. It’s broken code.

Now try this:

    String js = '''
      [1,2,3,4,5].forEach(function(n) {
        if(n === 3) {
          return n;  // WILL NOT WORK
        }
      });
      return 99;
    '''
    int n = WebUI.executeJavaScript(js, null)
    println "result: " + n

You’ll get 99 printed to the console. If you’ve understood what I was saying, it proves you cannot return a value from inside a genuine Array.forEach method. PERIOD.

Now, to answer your question (implied in the title of your post) - “Variable not receiving value from javascript”

  1. Your code as listed returns undefined.
  2. Groovy turns undefined into null
  3. You then assign null to audduration
  4. So your variable is receiving a value from JavaScript (just not the value you’re expecting because your code is invalid/not doing what you thought.)

After reviewing the code I initially submitted, it appears I pasted the wrong js. This is the code that is returning the correct value.

var title_cells = document.querySelectorAll(’.views-table tbody tr td.views-field-title’); title_cells.forEach(function(cell) {
if (cell.innerHTML.includes(‘AUD Entitlement Product’)) {
console.log(cell.nextElementSibling.innerHTML);
}
});
, null)

That code doesn’t return anything.

Yeah, because you’re not running it against the page on my website so there is no data for it to return. When run against the table shown in the attachment, it returns “2”, which is the correct value.

  1. I’m not running it anywhere, except in my head.
  2. That code does not return 2, it prints 2 to the console. Printing 2 and returning 2 a very different things.

Regardless, there is no return statement so it cannot return anything (except undefined when called from Groovy).

image

Jeff, I’m sorry, but if you are not going to listen to what I’m trying to teach you, I need to bow out of this cyclic (and frankly pretty pointless) conversation.

By way of courtesy, I’ll make a call out to a few other “code heads”, perhaps they can steer you straight:

@devalex88, @ThanhTo @Brandon_Hein @Marek_Melocik, @Andrej_Podhajsky

Good luck

I’m just the middle man between you and the developer I’m working with. I don’t know javascript nor do I understand it. I’m just relaying here. Also, I’m not trying to learn javascript right now, I’m just trying to get a value into a variable. Thanks.

I’m by no means a JS expert but I have a few suggestions that may help you narrow down the issue:

1.) Try something simple, like:

String test = WebUI.executeJavaScript("return 'Hello world!';", null);

If you get the appropriate value in ‘test’, then you know that it’s a problem with your JS, and not the WebUI method call.

2.) Try executing your JS directly through WebDriver, instead of the WebUI API:

WebDriver driver = DriverFactory.getWebDriver();
JavascriptExecutor executor = (JavascriptExecutor)driver;
String audduration = executor.executeScript("var title_cells = document.querySelectorAll('.views-table tbody tr td.views-field-title');
  title_cells.forEach(function(cell) { 
    if (cell.innerHTML.includes('AUD Entitlement Product')) { 
      return cell.innerHTML; 
    } 
})");

If you get the appropriate value returned here, then it’s either a bug in the WebUI.executeJavaScript() method, or an error in your usage of it.

If anyone is curious, here’s the WebUI.executeJavaScript() method implementation (which does basically what I’ve done in #2 from my previous post):

    @CompileStatic
    public Object executeJavascript(String script, List arguments, FailureHandling flowControl) {
        WebUIKeywordMain.runKeyword({
            WebDriver webDriver = getWebDriver()
            if (!(webDriver instanceof JavascriptExecutor)) {
                throw new StepFailedException(MessageFormat.format(CoreWebuiMessageConstants.KW_MSG_WEBDRIVER_DOES_NOT_SUPPORT_JS, webDriver.getClass().getName()))
            }
            JavascriptExecutor jsExecutor = (JavascriptExecutor) webDriver
            Object result = jsExecutor.executeScript(script, arguments != null ? arguments.toArray() : new Object[0])
            logger.logPassed(MessageFormat.format(CoreWebuiMessageConstants.KW_LOG_PASSED_EXECUTE_JS_SUCESSFULLY, script))
            return result
        }, flowControl, true, CoreWebuiMessageConstants.KW_MSG_UNABLE_TO_EXECUTE_JS)
    }

Valid code. Will return a string value “Hello world!”

But there’s no point, Brandon. His code does not return a value except undefined which is correct for that code when wrapped by Kat/Webdriver and inserted in the page. As I said earlier in the thread:

Jeff (and perhaps his developer?) think they can return early from .forEach, which, like .each in Groovy, means “visit them all” - there is no way to exit early.

1 Like

I think you’re probably right, just trying to address some unknowns. To your point, could he use a break; upon finding the correct element? Thinking something like:

var title_cells = document.querySelectorAll(".views-table tbody tr td.views-field-title");
var innerHTML;
title_cells.forEach(function(cell) { 
if (cell.innerHTML.includes("AUD Entitlement Product")) {
    innerHTML = cell.innerHTML;
    break;
} 
})
return innerHTML;

Nope. He needs the methods I showed him earlier:

This is probably the oldest/least-fashionable way to go about it…

  var title_cells = document.querySelectorAll('.views-table tbody tr td.views-field-title'); 
  for(var i = 0; i < title_cells.length; i++) {
    if (title_cells[i].innerHTML.includes('AUD Entitlement Product')) {
      return title_cells[i].nextElementSibling.innerHTML;
      //return title_cells[i].innerHTML;
    }
  }

Notice the two return statements - not sure which he needs.

But there’s no coverage for a completed loop there. Suggest returning -999 or something.

Yup, I see it. He needs to just use a simple for loop.

@Jeff_Sharp I think Russ has identified the issue; you need to use a normal for loop as he’s suggested. Try the JS code that he has provided and get back to us, thanks.

Jeff,
just one question, why the hell are you using such code?
you have selector, you have forEach loop, some condition and you are trying to get innerHtml of some cell … this can be quite nicely implemented using what Katalon already offers : Selenium and java/groovy…
maybe there is an reason however, i’m not able to see it …

1 Like

@Andrej_Podhajsky makes a fair and valid point. I guess JS is my hammer, and everything looks like a nail :blush:

No, it can’t be nicely implemented using what Katalon already offers, unless I’m missing something. The problem is that the rows in the table are assigned different identifiers/locators each time an account is created. Therefore I can’t easily identify the element each time I run the test, since the ID’s/etc will be different. Also, I need to verify that the Duration (see my example screenshot above in this thread) for each line item is correct. However, for some users there will be rows of data that do not need to be verified. So I need to first verify that a specific row needs the Duration verified and then to verify that Duration to make sure it matches what is expected. I could not figure out how to do this using what Katalon Studio provides, which is why the developer I asked about this suggested using Javascript and provided me with the code. According to Russ, that code is incorrect so I’m trying to use JS that actually does what I need it to do. One problem, however, is that I am not a Javascript developer so I don’t understand most of what Russ has explained or suggested. I’m turning this over to the developer that tried to help me earlier in hopes that she can figure all of this out. Hope that helps you understand what I’m trying to do.

now i’ll be a bit stubborn, let me think in ‘Katalonian’ for second…

  1. there is keyword that executes and returns value (shameless self promo) Execute xpath functions from Katalon Studio try to get inspiration in implementation
  2. what you need: number of all rows in table that contains text we need (don’t need id of row) - should be easy to build xpath for such query
  3. for loop to go thru all interested rows and check for column you are interested in using parameterized xpath
  4. assert return from WebUI.getText() expected value.

this would be my approach…

1 Like

to show what i’m talking about:

<table id='getVariable'>
			<tbody>
				<tr><td>0001</td><td>xxx-text to recognize</td><td>1975</td><td>other column</td></tr>
				<tr><td>0001</td><td>yyy-text to recognize</td><td>1975</td><td>other column</td></tr>
				<tr><td>0001</td><td>zzz-text to recognize</td><td>1975</td><td>other column</td></tr>
				<tr><td>0001</td><td>xxx-text to recognize</td><td>1977</td><td>other column</td></tr>
				<tr><td>0001</td><td>qqq-text to recognize</td><td>1975</td><td>other column</td></tr>
				<tr><td>0001</td><td>www-text to recognize</td><td>1975</td><td>other column</td></tr>
			</tbody>
		</table>

def of objects in OR:
rows to check:

rows to check assert

code:

import static com.kms.katalon.core.testobject.ObjectRepository.findTestObject

import com.kms.katalon.core.webui.keyword.WebUiBuiltInKeywords as WebUI

WebUI.openBrowser('file://C:/Users/XXXXX/src/html/hello.html')

def noOfRowsToCheck = CustomKeywords.'com.swre.tools.exexpath'(findTestObject('Object Repository/__Sandbox/HelloFile/rowsToCheck'), 'NUMBER_TYPE')

println noOfRowsToCheck

for (i = 1; i <= noOfRowsToCheck; i++){
	println WebUI.getText(findTestObject('Object Repository/__Sandbox/HelloFile/rowsToCheckAssert',[('INDEX'):i]))
}

console:

2019-04-24 08:06:22.587 DEBUG testcase.value check in table            - 1: openBrowser("file://C:/Users/XXXXXX/src/html/hello.html")
2019-04-24 08:06:24.581 DEBUG testcase.value check in table            - 2: noOfRowsToCheck = com.swre.tools.exexpath(findTestObject("Object Repository/__Sandbox/HelloFile/rowsToCheck"), "NUMBER_TYPE")
2019-04-24 08:06:24.825 DEBUG testcase.value check in table            - 3: println(noOfRowsToCheck)
2
2019-04-24 08:06:24.832 DEBUG testcase.value check in table            - 4: for ([i = 1, i <= noOfRowsToCheck, (i++)])
2019-04-24 08:06:24.835 DEBUG testcase.value check in table            - 1: println(getText(findTestObject("Object Repository/__Sandbox/HelloFile/rowsToCheckAssert", ["INDEX":i])))
1975
2019-04-24 08:06:24.993 DEBUG testcase.value check in table            - 1: println(getText(findTestObject("Object Repository/__Sandbox/HelloFile/rowsToCheckAssert", ["INDEX":i])))
1977