32

I have a html document in memory as a string. It contains a <script> tag with a little script that manipulates the dom. I now want to load that html page into selenium webdriver and get back the page after the script manipulates it. Since I have the html already in memory, I don't like the idea much of writing the html into a file and load it as file with driver.get("file://path/to/file"). So the question is, if there is a possibility to achieve what I want.

IF webdriver can't do it, maybe there is a possibility other than that?

Here comes an example:

<html><head>
<script type="text/javascript">
function fill(){
    var i = "secret"
    document.forms[0].elements[1].value=i
}
</script>
</head><body onload="fill()">
<form method="POST"><input type="hidden" name="he1" value="">
<input type="hidden" name="he2" value="">
</form></body></html>

Obviously, I want the webdriver to perform the dom manipulation and change the form according to the script.

Note this is just an example. The actual script I need to run does much more complicated things.

luksch
  • 11,497
  • 6
  • 38
  • 53

6 Answers6

43

If you don't want to create a file or load a URL before being able to replace the content of the page, you can always leverage the Data URLs feature, which supports HTML, CSS and JavaScript:

ChromeDriver driver = new ChromeDriver();
html_content = """
<html>
     <head></head>
     <body>
         <div>
             Hello World =)
         </div>
     </body>
</html>
"""

driver.get("data:text/html;charset=utf-8," + html_content)
jolancornevin
  • 999
  • 1
  • 9
  • 7
21

You could load an empty page eg:

<html></html>

And then set it's innerHTML

ChromeDriver driver = new ChromeDriver();
driver.get("file://empty-page.html");
String innerHtml = "<head>...</head><body onload="...">...</body>";
driver.executeScript("document.innerHTML = " + innerHtml);

Then fire the load event on the body

driver.executeScript("$(document.body).trigger('load');");

Then get the resultant HTML

String result = driver.executeScript("document.body.innerHTML;");
lance-java
  • 25,497
  • 4
  • 59
  • 101
19

this code can load any html string which include js and css.

html_bs64 = base64.b64encode(innerHtml.encode('utf-8')).decode()
driver.get("data:text/html;base64," + html_bs64)
moyang
  • 206
  • 2
  • 2
  • Thanks for answering. I can't test this at the moment. It looks similar to the solution that jolancornevin suggested in his answer 2 years ago. Anyone reading this and feels inclined to test it out, please report if this actually executes the Javascript as intended. – luksch Dec 25 '20 at 17:06
  • 1
    Hey @luksch I just tested and it indeed works, and better than the previous answer. – pojda Dec 29 '20 at 02:23
6

Using Java Selenium 2.4.2 I use the following to replace inner html of an existing element. I use the Apache StringEscapeUtils.escapeJavaScript to escape the HTML because this is a JavaScript replace of the inner html.

    public void replaceHTML(By by, String html) {
      WebElement e = driver.findElement(by);
      ((JavascriptExecutor) driver).executeScript("arguments[0].innerHTML='" + StringEscapeUtils.escapeJavaScript(html) + "'", e);
    }

Example html String I passed in.

<button type="button" onclick="alert('Hello world!')">Click Me!</button>

Notes:

  • I couldn't get "Lance Java's" approach to work because of invalid escaped characters. Adding a single quote after the equal sign fixed this problem.

  • I tested "Kenneth Baltrinic's" suggestion of using driver.get('about:blank'); but I wasn't able to write to the screen interacting with the base document. In java I had to use double quotes driver.get("about:blank"). I tested this with Chrome.

FolixOrision
  • 61
  • 1
  • 1
3

Just a small update: escapeEcmaScrip() replaces escapeJavaScript() in 2015.

public static void main(String[] args) throws InterruptedException{ 
    driver = new FirefoxDriver();
    driver.get("http://dhtmlx.com/docs/products/dhtmlxTree/");
    replaceHTML(By.xpath("//*/span[text()='Supported browsers:']"), "<button type=\"button\"  onclick=\"alert('Hello World!!')\">Click Me!</button>");
}

 private static void replaceHTML(By by, String html) {
      WebElement e = driver.findElement(by);
     ((JavascriptExecutor) driver).executeScript("arguments[0].innerHTML='" + StringEscapeUtils.escapeEcmaScript(html) + "'", e);

}
1

You could fire up jetty embedded. The jetty instance could then serve in memory html strings as web pages via a Servlet / Handler.

lance-java
  • 25,497
  • 4
  • 59
  • 101