Aritro Sen
Aritro Sen

Reputation: 357

Return value from Javascript function in Selenium webdriver

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 !

Upvotes: 3

Views: 7143

Answers (1)

billc.cn
billc.cn

Reputation: 7317

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.

Upvotes: 1

Related Questions