Is there any way to execute javascript functions from java code - javascript

I am trying to execute a javascript function from java code.
I used JavascriptExecutor from selenium package.
I tried below code
JavascriptExecutor js;
js.executeScript("let time;");
js.executeScript("time = 2;");
js.executeScript("function f(){console.log(time);}");
js.executeScript("f()");
This is output
Exception in thread "Thread 0"
org.openqa.selenium.JavascriptException: javascript error: f is not defined
Is there any way to execute the above script from java code? is it possible?

Try this:
String script = "let time;time = 2;function f(){console.log(time);}f()";
JavascriptExecutor js;
js.executeScript(script);

You can use window properties (or any built-in really) which will stick around:
js.executeScript("window.time = 4");
js.executeScript("window.f = () => console.log(window.time)");
js.executeScript("window.f()");

Related

Run external javascript code dynamically as a part of the script

I need to execute some javascript code from a string as a part of the current script.
I tried to do it with eval, but for example there is a problem with classes declaration
let code = "class A { test() {console.log('A class');} }; new A().test();";
eval(code);
new A().test();
In this example the A class will be instantiated successfully in the code from the code variable. But the next line execution will fail with
Uncaught ReferenceError: A is not defined
I need to do it like clear code injection from client side script (i.e. I can't use string formatting on the server-side for example).
Is there a method for it? Or is there an error in my eval usage?
I want to have a code like
// Do something
executeScript(getScriptFromUrl("scipr url here"));
let obj = new ClassFromScript();
obj.doSomething();

Node.js C++ add-on trying to execute javascript code with `require` function

I'm maintaining a Node.js add-on in C++.
I need to call a SQL parser (a very non-standard variant of SQL, actually) inside an asynchronously called C++ function, but unfortunately (for me) that parser has been implemented in Javascript using some Node.js libraries (the function require is being used); this is an example of the kind of javascript code I need to execute:
require("./util/SqlParser")("SELECT 1 FROM DUAL").getSyntaxTree()
I've tried writing something like this:
v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::Local<v8::Context> context = isolate->GetCurrentContext();
v8::TryCatch trycatch;
v8::Local<v8::String> source = v8::String::NewFromUtf8(isolate
,
"require(\"./util/SqlParser\")(\"SELECT 1 FROM DUAL\").getSyntaxTree()"
,
v8::NewStringType::kNormal).ToLocalChecked()
;
v8::Local<v8::Script> script = v8::Script::Compile(context, source).ToLocalChecked();
v8::MaybeLocal<v8::Value> result = script->Run(context);
if( result.IsEmpty() )
{
v8::Local<v8::Value> exc = trycatch.Exception();
if( !exc.IsEmpty() )
{
auto msg = exc->ToString();
if( !msg.IsEmpty() )
throw std::string( *v8::String::Utf8Value(msg) );
}
throw "unknown error in called js function";
}
But unfortunately this doesn't work. The net outcome is the error message "ReferenceError: require is not defined": apparently, my context doesn't know anything about Node.js.
I tried to wrap the above expression in a js function parseSqlText, but this function is equally unknown to the script executor (I get the error message "ReferenceError: parseSqlText is not defined").
My question is: is there any way to get around this?
Any help would be very appreciated. I would be very glad to avoid reimplementing that parser in C++... which at present seems the only viable way to do what I need.
First, v8 is not Node.js, Node.js is built on top of v8.
v8 is a javascript engine
Thus Node.js libraries are not carried with v8 by it-self
The N-API is the answer to question. Although, normally it is used to write native C++ plugins for Node.js. The github thread belwo has some examples. Additionally, the node.js docs for N-API have also been linked.
Github Thread
Node N-API Docs
EDIT: It would seem the work has been done already, here in this repository. The writer made it so it appears to abstract all the prep work of v8 and be one line for you.
#include "node_embed.h"
int main(int argc, char** argv) {
node_context *context = nodeSetup(argc, argv);
if (context) {
nodeExecuteString(context, "let foo = 1", "__init__");
nodeExecuteString(context, "foo = 2", "__init__");
nodeExecuteString(context, "console.log(foo)", "__init__");
return nodeTeardown(context);
} else {
return 12;
}
}
The above is from the repository and will allow you to run that snippet of code.
I suggest that you go find an SQL parser that is already written in C++. I found one immediately in a ten-second search on github.com.
In my opinion, there is zero technical justification for bringing the JavaScript language into this scenario, just to be able to "parse SQL." You will not have to "write from scratch" anything at all. It will just be an object – pluck it "off the shelf," instantiate an instance of it, and use it.

Kotlin Call Javascript function in Android without webView

Is there any way we can call JS function from Kotlin without having WebView in Android?
Let's say as mentioned below I have one JS function helloJS() in test.js file,
test.js:-
function helloJS(){
return "Hello from JS"
}
And now I want to call this function from Kotlin file like
TestClass.kt:-
class TestHello{
fun getHelloFromJS(){
val name = test.helloJS()
}
}
Till now I am using Webview and loading JS file into that and getting result as call back
But, I read that Kotlin is interoperable with JS like Java
So I am curious to know if there is any way we can use that on Android without having webView
This is not possible straight forward but I found one library Execute JavaScript in Android without WebView for achieve this.
Read that blog carefully and follow below step.
Keep your JavaScript file (test.js) in assets folder in android project.
I have converted that code into Kotlin.
CallJavaScript.jks
import org.mozilla.javascript.Context
import org.mozilla.javascript.Function
import java.io.InputStreamReader
object CallJavaScript {
fun callFunction(mContext: android.content.Context): Any? {
var jsResult: Any? = null
val params = arrayOf<Any>("")
// Every Rhino VM begins with the enter()
// This Context is not Android's Context
val rhino = Context.enter()
// Turn off optimization to make Rhino Android compatible
rhino.optimizationLevel = -1
try {
val scope = rhino.initStandardObjects()
// Note the forth argument is 1, which means the JavaScript source has
// been compressed to only one line using something like YUI
val assetManager = mContext.assets
try {
val input = assetManager.open("test.js")
val targetReader = InputStreamReader(input)
rhino.evaluateReader(scope, targetReader, "JavaScript", 1, null)
} catch (e: Exception) {
e.printStackTrace()
}
// Get the functionName defined in JavaScriptCode
val obj = scope.get("helloJS", scope)
if (obj is Function) {
// Call the function with params
jsResult = obj.call(rhino, scope, scope, params)
// Parse the jsResult object to a String
val result = Context.toString(jsResult)
}
} finally {
Context.exit()
}
return jsResult
}
}
Add this line to build.gradle:
implementation 'org.mozilla:rhino:1.7R4'
In your assets folder, create a file called test.js:
function helloJS()
{
return "Hello from JS";
}
Now simply call above function from Activity.
Log.e("JS : ", CallJavaScript.callFunction(this).toString());
Output :
E/JS :: Hello from JS
It's not possible. You must not confuse the language with the platform.
Kotlin is interoperable with JS like Java
means Kotlin/JS can use and be used in a Javascript platform (Node.js or browsers). The Kotlin code compiled (transpiled) into js is able to call other js files. And external Js code can call the js code build from Kotlin. This is the interoperability with JS.
There is no interoperability between Kotlin/JS and Kotlin/JVM.
Kt looks like JS, but it is not. It will be compiled for Android runtime, not for the java script engine.
JS code require a JS runtime, but it is not in Android Runtime.
i.e. you cannot run JS directly in Java / Kt code for Android.
Am not a pro in Kotlin but Java is a pie for me. Anything you can implement in Java can be implemented in Kotlin and To execute Javascript code, I use rhino which does the job pretty easier than using the webview
Implement it:
try {
Scriptable scope = rhino.initStandardObjects();
rhino.evaluateString(scope, javaScriptCode, "JavaScript", 1, null);
Object obj = scope.get(functionNameInJavaScriptCode, scope);
if (obj instanceof Function) {
Function jsFunction = (Function) obj;
// Call the function with params
Object jsResult = jsFunction.call(rhino, scope, scope, params);
// Parse the jsResult object to a String
String result = Context.toString(jsResult);
}
}finally {
Context.exit();
}

Can Javascript file access objects from Python objects running?

let say in Javascript file
_myclass = new MyClass();
MyClass is not defined anywhere in the Javascript.
However, MyClass is a class defined by setup.py and that setup.py is running.
setup(name = 'MyClass',
version = '1.0',
author = '123',
when setup.py is not running then MyClass would be undefined in JAvascript.
Does this make any sense?
You can use the Django framework. To simplify what it does, let say you can write any python class and/or function and pass it to an html template. So basically it allows you to put your python variables in your JS script.
Hope it helps!

Reading JavaScript variables using Selenium WebDriver

I'm using Selenium WebDriver (Java) and TestNG to do some testing on a website I created. In this website, I also have JavaScript and in some of the functions, it returns values and also outputs values to the browser console through console.log().
I was wondering if there is an easy way for Selenium WebDriver to access some of this JavaScript information so I can perform assertions using TestNG.
I'm quite new to Selenium but I understand that you can do something like:
WebDriver driver = new ChromeDriver();
driver.findElement(By.id("btn")).click();
So is there anything similar I can do using WebDriver to read the JavaScript on the site?
Clarification
It looks like people are making the assumption that I'm trying to "execute" JavaScript code through Selenium.
Thats not the case. Instead, I'm trying to store already-defined JavaScript variable using Selenium.
Basically, I want Selenium to be able to grab the JavaScript variable's value, store it locally, and then do an assertion test on it.
Attempt 1
Say I have the following JS code for my website:
$(document).ready(function() {
var foo = $(#"input-field-val").val();
function returnFoo() {
return foo;
}
});
From what I've reading and understanding, in my seperate Selenium test file (Selenium.java), I should be able to do something like this?:
public class Selenium {
WebDriver driver = new FirefoxDriver();
JavascriptExecutor js = (JavascriptExecutor) driver;
#Test
public void testSample() {
driver.get("www.mywebsite.com");
js.executeScript("alert(returnFoo());");
}
}
I do something similar to what's above but no alert box pops up. Instead, I get an error message:
Exception in thread "main" org.openqa.selenium.WebDriverException: ReferenceError: returnFoo is not defined
I'm pretty sure I'm not understanding what it means when its said that the JS variable
should not be part of a closure or local variable
I have also tried defining a global variable above the $(document).ready(function()... and setting is within function returnFoo() but still doesn't work.
Attempt 2
I've moved both foo and returnFoo() outside of the $(document).ready(function().... That has fixed ReferenceError message that I was getting in Attempt 1 above.
I hav also given foo a value so my JS code looks something like this:
var foo = "Selenium test run";
$(document).ready(function() {
...
});
function returnFoo() {
return foo;
}
Now, I'm having a tough time assigning the return of returnFoo() to a local variable within my Selenium test. Here's what I've attempted:
public static void main(String[] args) {
WebDriver driver = new FirefoxDriver();
JavascriptExecutor js = (JavascriptExecutor) driver;
driver.get("http://localhost:8080/HTML5TestApp/prod.html");
Object val = js.executeScript("window.returnFoo();");
System.out.println(val);
}
But the console display null instead of the actual value of "Selenium test run".
Attempt 2 - SOLUTION
It looks like if I do Object val = js.executeScript("alert(returnFoo());"); I get the value of foo.
SOLUTION
So here's the solution I've come up w/ to my problem thanks to the solution by Martin Foot below.
In my JavaScript file, I created a var and a setter/getter function like so:
index.js
var seleniumGlobal;
$(document).ready(function() {
...
)};
function setSG(toSet) {
seleniumGlobal = toSet;
}
function getSG() {
return seleniumGlobal;
}
SampleTest.java
// Do all the necessary imports
public class SampleTest {
WebDriver driver = new FirefoxDriver();
JavascriptExecutor js = (JavascriptExecutor) driver;
#Test
public void testPrintVal() {
String sgVal = (String) js.executeScript("alert(getSG());");
Assert.assertEquals("new value for seleniumGlobal", sgVal);
}
}
So whenever some code in my JavaScript sets my seleniumGlobal variable through the setter method, I can call it through my Selenium test and do assertions on it.
This is probably not the most efficient way to do but if someone else has a better solution, please let me know.
All you have to do is:
Object val = js.executeScript("return returnFoo();");
That will give you what you are looking for.
No JavaScript functions need be defined. Nor is alert() needed.
Object result = js.executeScript("return globalVar");
For Python:
result = driver.execute_script("return globalVar")
In Ruby you can use page.execute_script to evaluate a JavaScript variable (if it is accessable from the scope of the web browser). It looks like there is a similar method in Java here.
Edit: This might be a use case that is more suited to a JavaScript unit testing framework such as Jasmine.

Categories

Resources