I'm in Eclipse, programming a Java GUI/script, running a headless chromedriver and I'm having issues with trying to load the html2canvas.js [1] [2] library in the driver, then calling a function I wrote on that library in the browser; I'm getting an undefined error with this code:
String ss1ScriptLoc = "C:\\Users\\me\\Desktop\\resources\\html2canvas.min.js";
String ss2ScriptLoc = "C:\\Users\\me\\Desktop\\resources\\takeScreenShot.js";
je.executeScript(
"var headID1 = document.getElementsByTagName('head')[0]; "
+ "var newScript1 = document.createElement('script'); "
+ "newScript1.type = 'text/javascript'; "
+ "newScript1.src = '" + ss1ScriptLoc + "'; "
+ "headID1.appendChild(newScript1); "
+ "var headID2 = document.getElementsByTagName('head')[0]; "
+ "var newScript2 = document.createElement('script'); "
+ "newScript2.type = 'text/javascript'; "
+ "newScript2.src = '" + ss2ScriptLoc + "'; "
+ "headID2.appendChild(newScript2); "
+ "$(document).ready( function () { takeScreenShot(); });"
);
This results in an error for not defining the function "takeScreenShot();" which I thought I defined already in the local .js files.
Starting ChromeDriver 75.0.3770.140 (-refs/branch-heads/3770@{#1155}) on port 48415
Only local connections are allowed.
Please protect ports used by ChromeDriver and related test frameworks to prevent access by malicious code.
Aug 05, 2019 9:36:53 AM org.openqa.selenium.remote.ProtocolHandshake createSession
INFO: Detected dialect: W3C
java.util.concurrent.ExecutionException: org.openqa.selenium.JavascriptException: javascript error: takeScreenShot is not defined
(Session info: headless chrome=75.0.3770.142)
Caused by: org.openqa.selenium.JavascriptException: javascript error: takeScreenShot is not defined
(Session info: headless chrome=75.0.3770.142)
Build info: version: '3.141.59', revision: 'e82be7d358', time: '2018-11-14T08:25:48'
System info: host: '', ip: '', os.name: 'Windows 10', os.arch: 'amd64', os.version: '10.0', java.version: '1.8.0_191'
Driver info: org.openqa.selenium.chrome.ChromeDriver
Capabilities {acceptInsecureCerts: false, browserName: chrome, browserVersion: 75.0.3770.142, chrome: {chromedriverVersion: 75.0.3770.140 (2d9f97485c7b..., userDataDir: C:\Users\me\AppData\Lo...}, goog:chromeOptions: {debuggerAddress: localhost:55906}, javascriptEnabled: true, networkConnectionEnabled: false, pageLoadStrategy: normal, platform: XP, platformName: XP, proxy: Proxy(), setWindowRect: true, strictFileInteractability: false, timeouts: {implicit: 0, pageLoad: 300000, script: 30000}, unhandledPromptBehavior: dismiss and notify}
Session ID:
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at org.openqa.selenium.remote.http.W3CHttpResponseCodec.createException(W3CHttpResponseCodec.java:187)
at org.openqa.selenium.remote.http.W3CHttpResponseCodec.decode(W3CHttpResponseCodec.java:122)
at org.openqa.selenium.remote.http.W3CHttpResponseCodec.decode(W3CHttpResponseCodec.java:49)
at org.openqa.selenium.remote.HttpCommandExecutor.execute(HttpCommandExecutor.java:158)
at org.openqa.selenium.remote.service.DriverCommandExecutor.execute(DriverCommandExecutor.java:83)
at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:552)
at org.openqa.selenium.remote.RemoteWebDriver.executeScript(RemoteWebDriver.java:489)
at App.getScreenShot(App.java:170)
at javax.swing.SwingWorker$1.call(SwingWorker.java:295)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at javax.swing.SwingWorker.run(SwingWorker.java:334)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
edit1: added this snippet in, tested, works, but doesn't appear to actually do anything.
je.executeScript("");
je.executeScript("document.body.onload = myCustomFunc();"
+ "function myCustomFunc() { console.log('hello world'); }"
);
I took the two library .js files and read them into List then made one big StringBuilder that had all the elements appended to the StringBuilder, then added the takeScreenShot() function inplace of myCustomFunc(). Doesn't throw any errors, but doesn't produce a downloaded screenshot file either.
edit2: my loading function
private String fileToJSString(final String inScriptFile) {
Path p = Paths.get(inScriptFile);
if (!Files.exists(p)) {
System.err.println("fileToJSString : error, file does not exist");
return null;
}
List<String> lines = null;
try {
lines = Files.readAllLines(Paths.get(inScriptFile));
} catch (IOException e) {
e.printStackTrace();
}
if (lines == null) {
System.err.println("fileToJSString : error, no lines read from file");
return null;
}
StringBuilder sb = new StringBuilder();
for (String s : lines)
sb.append(s.trim() + " ");
return sb.toString();
}
edit3: as per the suggestion by @jay-mattinson I attempted to load the scripts, however the runtime String variable doesn't work with the html2canvas.js library (too many special characters - see the link to the actual file earlier/above in this post)
String ss1ScriptLoc = "C:\\Users\\me\\Desktop\\resources\\html2canvas.min.js";
String ss2ScriptLoc = "C:\\Users\\me\\Desktop\\resources\\takeScreenShot.js";
String jsScript1 = fileToJSString(ss1ScriptLoc);
String jsScript2 = fileToJSString(ss2ScriptLoc);
JavascriptExecutor je = (JavascriptExecutor) this.driver;
je.executeScript(
"var headID = document.getElementsByTagName('head')[0]; "
+ "var newScript = document.createElement('script'); "
+ "newScript.type = 'text/javascript'; "
+ "var code = {" + jsScript1 + " " + jsScript2 + "};"
+ "newScript.appendChild(document.createTextNode(code));"
+ "headID.appendChild(newScript); "
+ "$(document).ready( function () { takeScreenShot(); });"
);
Specific error thrown during runtime;
Caused by: org.openqa.selenium.WebDriverException: unknown error: Runtime.evaluate threw exception: SyntaxError: Unexpected token !
edit4: here's the html2canvas based function I wrote to grab an image of a table on a webpage;
function takeScreenShot() {
if (document.getElementsByClassName("abc-top") == null) {
console.log('not on the right web page with the right content. stopping script');
return;
}
var hiddenLinkObj = document.createElement('a');
hiddenLinkObj.setAttribute('href', '');
hiddenLinkObj.setAttribute('id', '');
document.body.insertBefore(hiddenLinkObj, document.body.childNodes[0]);
var s1 = window.location.href;
var idx = s1.lastIndexOf('/');
var res = s1.substring(idx + 1, s1.length);
hiddenLinkObj.setAttribute('download', 's' + res + '-s.png');
var partA = document.querySelector('[abc-show="showInfo"]');
var partB = partA.getElementsByClassName('row');
var partC = partB[3].childNodes[0];
partC.setAttribute('style', 'background-color:#fafafa');
var result = partC;
html2canvas(
result, {
onrendered: function(canvas) {
var myImage = canvas.toDataURL("image/png");
hiddenLinkObj.setAttribute('href', myImage.replace("image/png", "image/octet-stream"));
hiddenLinkObj.click();
}
}
);
}
So my question/issue: why is there an undefined function error when it's being defined and loaded in the takeScreenShot.js file? - How do I load a decent size html2canvas JS library and a second/short library containing a single JS function I wrote based off the html2canvas library and execute my function inside selenium? -
I'm guessing it lies in my lack of JavaScript knowledge and I'm missing an obvious error. Any and all help appreciated.