3

How do i return an array from a javascript function using selenium webdriver ? the code which i have tried is -

System.setProperty("webdriver.chrome.driver", "D:/chromedriver_win32/chromedriver.exe");
    wd=new ChromeDriver();
    wd.navigate().to("http://www.makemytrip.com");
    wd.manage().window().maximize();
    Thread.sleep(5000);
    wd.findElement(By.id("from_typeahead1")).click();
    WebElement span= wd.findElement(By.xpath(".//*[@id='one_round_default']/div/div[1]/div/div[1]/span/span/div[1]/span"));

    JavascriptExecutor jse = (JavascriptExecutor)wd;
    jse.executeScript("window.showList = function(){"+
            "var source=[];"+
            "var inputs = arguments[0].getElementsByTagName('div');"+
            "for(var i = 0; i < inputs.length; i++) {"+
                "source.push(inputs[i])"+
            "}"+
            "return source;"+
            "};",span);

    /*List<?> al =  (List<?>) jse.executeScript(
            "var source = [];"+
            "var inputs = arguments[0].getElementsByTagName('div');"+
            "for(var i = 0; i < inputs.length; i++) {"+
               "source.push(inputs[i])"+      
            "}"+
            "return source;"                 
            ,span);*/

    List<?> al =  (List<?>) jse.executeScript("showList();");
    for(Object web:al){
        System.out.println(((WebElement) web).getText());
    }

I am getting an exception stating - "org.openqa.selenium.WebDriverException: unknown error: Cannot read property 'getElementsByTagName' of undefined."

Incidently when i try this code it works perfectly -

System.setProperty("webdriver.chrome.driver", "D:/chromedriver_win32/chromedriver.exe");
    wd=new ChromeDriver();
    wd.navigate().to("http://www.makemytrip.com");
    wd.manage().window().maximize();
    Thread.sleep(5000);
    wd.findElement(By.id("from_typeahead1")).click();
    WebElement span= wd.findElement(By.xpath(".//*[@id='one_round_default']/div/div[1]/div/div[1]/span/span/div[1]/span"));

    List<?> al =  (List<?>) jse.executeScript(
            "var source = [];"+
            "var inputs = arguments[0].getElementsByTagName('div');"+
            "for(var i = 0; i < inputs.length; i++) {"+
               "source.push(inputs[i])"+      
            "}"+
            "return source;"                 
            ,span);

    for(Object web:al){
        System.out.println(((WebElement) web).getText());
    }

But i want to first create a function which returns me the array and then call the function whenever i want. How to achieve that? Also if possible how do i use an external .js file to do the same logic and use it in my script? Any help will be greatly appreciated. Thanks in advance !

1 Answer 1

1

As you have found out the executeScript method creates a function using the first argument and pass the remaining arguments to it.

To break out of the scope of this function, simply define something in the global object or manipulate the DOM.

For example, call the jse.executeScript("window.showList = function(){... from your first code snippet somewhere in your test but do not pass it the span argument. This defines the showList function in the global scope.

Later you can simply do jse.executeScript("return showList.apply(null, arguments)", span) to call it.

Similarly, you can include an external script using the snippet

driver.executeScript("var s = document.createElement('script'); s.type = 'text/javascript'; s.src = arguments[0]; document.body.appendChild(s);", scriptUrl);

(or simply hard-code the url).

For both cases, remember to only run the definition/include call once to avoid redefining things.

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

5 Comments

Thanks @billc.cn ! Can you please show me a working example of the external .js file which you are creating and then calling it inside the script ? May be i am doing something wrong (syntax error i guess) for which its not working.
I don't really have a working example at hand, but basically you define global functions in the external script and call them using executeScript similar to the second example I gave above. You can use your browser's debug console to look for JS error (put some break points in your test code so you have time to interact with the browser). If you don't have access to the browser, you can get browser console logs for most drivers. Just google browser name + "selenium logs".
Okay will try. Thanks again ! Just one more thing - do i need to put the external .js file in local webserver or can i access it from local resources ? if so how do i assign the path in "s.src" ?
The most simple way is to serve it from where the main website is served. If not possible, you'll have to run another HTTP server to host it as most browsers refuse to load resources using the file: protocol for pages served with http:. As a last resort, you can make your test code read the script file and insert it as a <script> block using executeScript. However, escaping the script can become quite tricky here.
Ok. That explains it. I was trying to load the.js file from local machine using the "file:" protocol and it was throwing "function undefined" exception. Thanks again @billc.cn !

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.