public boolean WaitForPageToLoad(){
final ExpectedCondition<Boolean> pageLoadCondition = new ExpectedCondition<Boolean>() {
public Boolean apply(final WebDriver driver) {
return ((JavascriptExecutor) driver).executeScript("return document.readyState").equals("complete");
}
};
final WebDriverWait wait = new WebDriverWait(this.driver, this.defaultTimeoutinSeconds);
final boolean IsPageLoad = wait.until(pageLoadCondition);
if (!IsPageLoad) {
log.logInfo("Page doesn't load after " + this.defaultTimeoutinSeconds + " seconds");
}
return IsPageLoad;
}
above code was working in selenium 2.53.1 but when I upgraded to Selenium 3.1.X, above code is not compatible. Plaese anyone convert above code to make it compatible with selenium 3. I am getting below error
The method until(Function) in the type FluentWait is not applicable for the arguments (new ExpectedCondition(){})
This code works for me for Selenium3
driver = (new Driver(Driver.Browser.SAFARI)).getDriver();
driver.navigate().to("http://www.epochconverter.com/");
waitForLoad(driver);
static void waitForLoad(WebDriver driver) {
new WebDriverWait(driver, 50).until((ExpectedCondition<Boolean>) wd ->
((JavascriptExecutor) wd).executeScript("return document.readyState").equals("complete"));
}
Related
I want to retrieve data from a website using Nashorn script engine
I have the java code where I can retrieve data from a sample website template.
Now I want to call that java file from java script file.
following is the code:
JAVA CODE(Nsample.java):
package sample;
import java.net.*;
import java.io.*;
public class Nsample
{
public static void main(String[] args)
{
String output = getUrlContents("https://freewebsitetemplates.com/");
System.out.println(output);
}
public static String getUrlContents(String theUrl)
{
StringBuilder content = new StringBuilder();
try
{
URL url = new URL(theUrl);
URLConnection urlConnection = url.openConnection();
BufferedReader bufferedReader = new BufferedReader(new
InputStreamReader(urlConnection.getInputStream()));
String line;
while ((line = bufferedReader.readLine()) != null)
{
content.append(line + "\n");
}
bufferedReader.close();
}
catch(Exception e)
{
e.printStackTrace();
}
return content.toString();
}
}
JAVASCRIPT code:(sample.js)
var n = Java.type('C.JavaFolder.sample.Nsample');
var result = n.getUrlContents("https://freewebsitetemplates.com/");
print(result);
I'm trying to compile javascript code using command prompt but it is showing CLASSNOTFOUNDEXCEPTION.
The command was jjs sample.js.Im assuming I did some mistake in Java.type() function.
Can anyone solve this?
This line is the problematic line:
var n = Java.type('C.JavaFolder.sample.Nsample');
Java.type accepts fully qualified java type name. Based on your Java code, your package seems to be "sample" and class name is "Nsample". So the fully qualified class name would be "sample.Nsample".
You should compile your Java classes and specify the directory in -classpath option (of jjs tool or your java application if you use javax.script API with nashorn).
Instead of calling Java from JavaScript , I tried to call JavaScript from java and worked well.
I created some functions in JavaScript and invoked those functions from Java code.
Following is the code.Hope this helps.
Test.java:
import javax.script.*;
import java.io.*;
import java.util.*;
public class Test{
public static void main(String[] args) throws Exception{
ScriptEngine engine = new ScriptEngineManager().getEngineByName("Nashorn");
engine.eval(new FileReader("test.js"));
Invocable invoke = (Invocable)engine;
Object res = invoke.invokeFunction("httpGet","https://www.javaworld.com");
System.out.println(res);
}
}
test.js:
var httpGet = function(theUrl){
var con = new java.net.URL(theUrl).openConnection();
con.requestMethod = "GET";
return asResponse(con);
}
function asResponse(con){
var d = read(con.inputStream);
return d;
}
function read(inputStream){
var inReader = new java.io.BufferedReader(new
java.io.InputStreamReader(inputStream));
var inputLine;
var response = new java.lang.StringBuffer();
while ((inputLine = inReader.readLine()) != null) {
response.append(inputLine);
}
inReader.close();
return response.toString();
}
Below is the snippet and getting error as follows :
The method executeScript(String, Object[]) in the type JavascriptExecutor is not applicable for the arguments (String)
Code Snippet :
public class ScrollPage {
public static void main(String[] args) {
System.setProperty("webdriver.chrome.driver", "C:\\SeleniumWorkSpace\\chromeDriver\\chromedriver.exe");
WebDriver driver = new ChromeDriver();
System.out.println(driver);
driver.get("https://en.wikipedia.org/wiki/Main_Page");
driver.manage().window().maximize();
JavascriptExecutor js = (JavascriptExecutor)driver;
js.executeScript("scroll(0,2500)");
}
}
How would I fix this?
Try to use it without casting
driver.executeScript("scroll(0,2500)");
Edit the line of code as :
//import
import org.openqa.selenium.JavascriptExecutor;
//cast driver instance to JavascriptExecutor
JavascriptExecutor js = (JavascriptExecutor)driver;
//invove executeScript method
js.executeScript("scroll(0, 2500)");
Note : Put a space between the coordinates
Try this code:
JavascriptExecutor js = (JavascriptExecutor)driver;
js.executeScript("window.scrollTo(0,2500);");
Please try the following - I was having the same error with JavascriptExecutor not performing scroll downs properly.
public WebElement pollingScroll(By locator) {
WebDriverWait shortWait = new WebDriverWait(driver, 1);
WebElement element = null;
while(element == null) {
((JavascriptExecutor) driver).executeScript("window.scrollBy(0, 555);");
try {
element =
shortWait.until(ExpectedConditions.elementToBeClickable(locator));
} catch(Exception e) {}
}
return element;
}
I've been working on a problem with doing a synchronous call to JavaScript in a WebView (with a return value) and trying to narrow down the where and why of why it's not working. It seems to be that the WebView thread is blocking while the main thread is waiting for a response from it -- which shouldn't be the case since theWebView runs on a separate thread.
I've put together this small sample that demonstrates it (I hope) fairly clearly:
main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:weightSum="1">
<WebView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/webView"/>
</LinearLayout>
MyActivity.java:
package com.example.myapp;
import android.app.Activity;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.JavascriptInterface;
import android.webkit.WebViewClient;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class MyActivity extends Activity {
public final static String TAG = "MyActivity";
private WebView webView;
private JSInterface JS;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
webView = (WebView)findViewById(R.id.webView);
JS = new JSInterface();
webView.addJavascriptInterface(JS, JS.getInterfaceName());
WebSettings settings = webView.getSettings();
settings.setJavaScriptEnabled(true);
webView.setWebViewClient(new WebViewClient() {
public void onPageFinished(WebView view, String url) {
Log.d(TAG, JS.getEval("test()"));
}
});
webView.loadData("<script>function test() {JSInterface.log(\"returning Success\"); return 'Success';}</script>Test", "text/html", "UTF-8");
}
private class JSInterface {
private static final String TAG = "JSInterface";
private final String interfaceName = "JSInterface";
private CountDownLatch latch;
private String returnValue;
public JSInterface() {
}
public String getInterfaceName() {
return interfaceName;
}
// JS-side functions can call JSInterface.log() to log to logcat
#JavascriptInterface
public void log(String str) {
// log() gets called from Javascript
Log.i(TAG, str);
}
// JS-side functions will indirectly call setValue() via getEval()'s try block, below
#JavascriptInterface
public void setValue(String value) {
// setValue() receives the value from Javascript
Log.d(TAG, "setValue(): " + value);
returnValue = value;
latch.countDown();
}
// getEval() is for when you need to evaluate JS code and get the return value back
public String getEval(String js) {
Log.d(TAG, "getEval(): " + js);
returnValue = null;
latch = new CountDownLatch(1);
final String code = interfaceName
+ ".setValue(function(){try{return " + js
+ "+\"\";}catch(js_eval_err){return '';}}());";
Log.d(TAG, "getEval(): " + code);
// It doesn't actually matter which one we use; neither works:
if (Build.VERSION.SDK_INT >= 19)
webView.evaluateJavascript(code, null);
else
webView.loadUrl("javascript:" + code);
// The problem is that latch.await() appears to block, not allowing the JavaBridge
// thread to run -- i.e., to call setValue() and therefore latch.countDown() --
// so latch.await() always runs until it times out and getEval() returns ""
try {
// Set a 4 second timeout for the worst/longest possible case
latch.await(4, TimeUnit.SECONDS);
} catch (InterruptedException e) {
Log.e(TAG, "InterruptedException");
}
if (returnValue == null) {
Log.i(TAG, "getEval(): Timed out waiting for response");
returnValue = "";
}
Log.d(TAG, "getEval() = " + returnValue);
return returnValue;
}
// eval() is for when you need to run some JS code and don't care about any return value
public void eval(String js) {
// No return value
Log.d(TAG, "eval(): " + js);
if (Build.VERSION.SDK_INT >= 19)
webView.evaluateJavascript(js, null);
else
webView.loadUrl("javascript:" + js);
}
}
}
When running, the following results:
Emulator Nexus 5 API 23:
05-25 13:34:46.222 16073-16073/com.example.myapp D/JSInterface: getEval(): test()
05-25 13:34:50.224 16073-16073/com.example.myapp I/JSInterface: getEval(): Timed out waiting for response
05-25 13:34:50.224 16073-16073/com.example.myapp D/JSInterface: getEval() =
05-25 13:34:50.225 16073-16073/com.example.myapp I/Choreographer: Skipped 239 frames! The application may be doing too much work on its main thread.
05-25 13:34:50.235 16073-16150/com.example.myapp I/JSInterface: returning Success
05-25 13:34:50.237 16073-16150/com.example.myapp D/JSInterface: setValue(): Success
(16073 is 'main'; 16150 is 'JavaBridge')
As you can see, the main thread times out waiting for theWebView to call setValue(), which it doesn't until latch.await() has timed out and main thread execution has continued.
Interestingly, trying with an earlier API level:
Emulator Nexus S API 14:
05-25 13:37:15.225 19458-19458/com.example.myapp D/JSInterface: getEval(): test()
05-25 13:37:15.235 19458-19543/com.example.myapp I/JSInterface: returning Success
05-25 13:37:15.235 19458-19543/com.example.myapp D/JSInterface: setValue(): Success
05-25 13:37:15.235 19458-19458/com.example.myapp D/JSInterface: getEval() = Success
05-25 13:37:15.235 19458-19458/com.example.myapp D/MyActivity: Success
(19458 is 'main'; 19543 is 'JavaBridge')
Things work correctly in sequence, with getEval() causing the WebView to call setValue(), which then exits latch.await() before it times out (as you'd expect/hope).
(I've also tried with an even earlier API level, but things crash out due to what may be, as I understand it, an emulator-only bug in 2.3.3 that never got fixed.)
So I'm at a bit of a loss. In digging around, this seems like the correct approach to doing things. It certainly seems like the correct approach because it works properly on API level 14. But then it's failing on later versions — and I've tested on 5.1 and 6.0 without success.
Look more about migration WebView with Android 4.4.
See description on Android Docs I think you need to use another method for funning your JS action.
For example, base on that doc - Running JS Async Asynchronously evaluates JavaScript in the context of the currently displayed page. If non-null, |resultCallback| will be invoked with any result returned from that execution. This method must be called on the UI thread and the callback will be made on the UI thread.
I try to route on TomTom maps and get a callback from the routing method.
So I made up a Java Application in JavaFx and showed the TomTom Map on my webview from JavaFX.
Now my issue: I do call a method in Javascript from JavaCode and want to get the response from the routing method, but this takes time and is asynchronous. And I just get the Promise Object from javascript and not the response...
I changed the javscript functions and don't work with promises anymore.
Edited Code:
JavaCode:
package application;
import java.io.BufferedInputStream;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.Properties;
import javafx.application.Application;
import javafx.concurrent.Worker.State;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import netscape.javascript.JSObject;
public class Main extends Application{
static JSObject window;
static Stage primaryStage;
public void start(Stage primaryStage) {
try {
Browser browser = new Browser();
browser.getWebEngine().getLoadWorker().stateProperty()
.addListener((obs, oldValue, newValue) -> {
if (newValue == State.SUCCEEDED) {
window = (JSObject) browser.getWebEngine().executeScript("window");
System.out.println("Now call gogo");
System.out.println("gogo Output: " + window.call("gogo"));
WebController webControl= new WebController(browser, window);
window.setMember("clickController", webControl);
System.out.println("First it will go over here and print this");
LocalDate date = LocalDate.now();
try {
FileWriter fw = new FileWriter("output/"+date+".csv", true);
BufferedWriter bw = new BufferedWriter(fw);
bw.append(LocalTime.now() + ";" + delay + "\n");
bw.close();
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
});
Scene scene = new Scene(browser, Color.web("#666970"));
primaryStage.setTitle("TestApplication");
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
Javascript:
function gogo(){
var data = goTask(function(data) {
console.log(data.summary.totalDistanceMeters);
clickController.print("after all that java stuff it will invoke this syso")
clickController.print("output Routing function: " + data.summary.totalDistanceMeters);
clickController.print("gogo output with invoking java from javascript");
return data;
});
return data;
}
function goTask(call){
function callback(d){
call(d);
}
routeMe(callback);
function routeMe(callbackFunc){
var points = [ [48.7061643,9.1664228], [48.7322085,9.0489835] ];
var service = new tomtom.services.RoutingService("'ApiKey'");
var options = {
includeTraffic: true
// avoidTolls: true
};
service.getRoute(points, options,callbackFunc);
}
}
Output:
Now call gogo
gogo Output: undefined
First it will go over here and print this syso
WebController Syso: after all that java stuff it will invoke this
WebController Syso: output Routing function: 9419
WebController Syso: gogo output with invoking java from javascript
The problem is that Java does not wait on Javascript...
Can anyone help me?
Edit:
#Bonatti I am running it on
ScriptEngineFactory getEngine --> Oracle Nashorn
ScriptEngine getLanguage --> ECMAScript
Right now you are returning a Promise to Java, which doesn't know what to do with it. It won't wait for the promise to be fulfilled, and since there's no way of it interpreting the promise not much happens.
You can only handle this promise within Javascript, with something like .then( ... ), wherein you actually handle the result you expect right now (the delay).
Forcing the promise to be used synchronously will not work, it would be the same issue if you would want to handle your function result synchronously within Javascript (Call An Asynchronous Javascript Function Synchronously).
Try #Evan Knowles' answer here but with your callback instead:
We're going to set a listener for the successful state - basically we're going to inject a Java class into the JavaScript and have it call us back. Let's create a WebController that checks what is passed in and prints out the ID
How to catch return value from javascript in javafx?
I do not know the tomtom service. But from reading your code return new Promise is working as intended, as you are receiving the Promise
I would suggest having another function to receive the route then use a SOAP to read the data into your application
How is this achieved? Here it says the java version is:
WebDriver driver; // Assigned elsewhere
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("return document.title");
But I can't find the C# code to do this.
The object, method, and property names in the .NET language bindings do not exactly correspond to those in the Java bindings. One of the principles of the project is that each language binding should "feel natural" to those comfortable coding in that language. In C#, the code you'd want for executing JavaScript is as follows
IWebDriver driver; // assume assigned elsewhere
IJavaScriptExecutor js = (IJavaScriptExecutor)driver;
string title = (string)js.ExecuteScript("return document.title");
Note that the complete documentation of the WebDriver API for .NET can be found at this link.
I prefer to use an extension method to get the scripts object:
public static IJavaScriptExecutor Scripts(this IWebDriver driver)
{
return (IJavaScriptExecutor)driver;
}
Used as this:
driver.Scripts().ExecuteScript("some script");
the nuget package Selenium.Support already contains an extension method to help with this. Once it is included, one liner to executer script
Driver.ExecuteJavaScript("console.clear()");
or
string result = Driver.ExecuteJavaScript<string>("console.clear()");
How about a slightly simplified version of #Morten Christiansen's nice extension method idea:
public static object Execute(this IWebDriver driver, string script)
{
return ((IJavaScriptExecutor)driver).ExecuteScript(script);
}
// usage
var title = (string)driver.Execute("return document.title");
or maybe the generic version:
public static T Execute<T>(this IWebDriver driver, string script)
{
return (T)((IJavaScriptExecutor)driver).ExecuteScript(script);
}
// usage
var title = driver.Execute<string>("return document.title");
You could also do:
public static IWebElement FindElementByJs(this IWebDriver driver, string jsCommand)
{
return (IWebElement)((IJavaScriptExecutor)driver).ExecuteScript(jsCommand);
}
public static IWebElement FindElementByJsWithWait(this IWebDriver driver, string jsCommand, int timeoutInSeconds)
{
if (timeoutInSeconds > 0)
{
var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(timeoutInSeconds));
wait.Until(d => d.FindElementByJs(jsCommand));
}
return driver.FindElementByJs(jsCommand);
}
public static IWebElement FindElementByJsWithWait(this IWebDriver driver, string jsCommand)
{
return FindElementByJsWithWait(driver, jsCommand, s_PageWaitSeconds);
}
public void javascriptclick(String element)
{
WebElement webElement=driver.findElement(By.xpath(element));
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("arguments[0].click();",webElement);
System.out.println("javascriptclick"+" "+ element);
}
public static class Webdriver
{
public static void ExecuteJavaScript(this IWebDriver driver, string scripts)
{
IJavaScriptExecutor js = (IJavaScriptExecutor)driver;
js.ExecuteScript(scripts);
}
public static T ExecuteJavaScript<T>(this IWebDriver driver, string scripts)
{
IJavaScriptExecutor js = (IJavaScriptExecutor)driver;
return (T)js.ExecuteScript(scripts);
}
}
In your code you can then do:
IWebDriver driver = new WhateverDriver();
string test = driver.ExecuteJavaScript<string>(" return 'hello World'; ");
int test = driver.ExecuteJavaScript<int>(" return 3; ");
Please use the below extension methods added to execute javascript and to take screenshot in Selenium.Support (.dll) of Selenium C#
https://www.nuget.org/packages/Selenium.Support/
IWebDriver driver = new ChromeDriver();
driver.Manage().Window.Maximize();
driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(20);
driver.Url = "https://phptravels.net/";
driver.ExecuteJavaScript("document.querySelector('#checkin').value='07-12-2022'");
driver.ExecuteJavaScript("document.querySelector('#checkout').value='17-12-2022'");
IWebElement ele1 = driver.FindElement(By.Id("checkin"));
driver.ExecuteJavaScript("arguments[0].value='07-12-2022'",ele1);
string output=driver.ExecuteJavaScript<string>("return
document.querySelector('#checkin').value");
Console.WriteLine(output);
Screenshot sc= driver.TakeScreenshot();
sc.SaveAsFile("C:\\error.png");
The shortest code
ChromeDriver drv = new ChromeDriver();
drv.Navigate().GoToUrl("https://stackoverflow.com/questions/6229769/execute-javascript-using-selenium-webdriver-in-c-sharp");
drv.ExecuteScript("return alert(document.title);");