Freaky: Selenium RC works within HTMLUnit

View: New views
2 Messages — Rating Filter:   Alert me  

Freaky: Selenium RC works within HTMLUnit

by dfabulich :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


HTMLUnit is a popular Java-based browser simulator with excellent
JavaScript support.  Selenium RC is a popular in-browser testing tool
written entirely in JavaScript.  Today I tried using the HTMLUnit
simulated browser together with Selenium RC, running the Selenium
JavaScript inside of the HTMLUnit browser, and it worked!  I was able to
run/pass the GoogleTest (which simply browses to google.com and searches
for "selenium").

We don't use any of the HTMLUnit APIs for this test; instead, we do the
whole thing in JavaScript, communicating with the simulated HTMLUnit
browser over AJAX, just like we do with a real browser.

My GoogleTest launches HTMLUnit as a separate process using *custom; the
process's App basically does this:

WebClient wc = new WebClient(BrowserVersion.INTERNET_EXPLORER_7_0,
     "localhost", 4444);
wc.getPage(args[0]);

I've attached code that you should be able to use.

Also, there's a few catches, as you might expect.

1) HTMLUnit bug 1784330 (ActiveXObject is incorrectly case sensitive).

http://sourceforge.net/tracker/index.php?func=detail&aid=1784330&group_id=47038&atid=448266
http://tinyurl.com/3xxkrs

To workaround this, you'll need to patch xmlextras.js to refer to the
ActiveXObject as "Msxml2.XMLHTTP" instead of "MSXML2.XmlHttp" as we do
currently.

2) It's slow

The standard Google test took 25 seconds to run; this test normally gets
done in less than 10 seconds on my laptop.  I don't think this is going to
be too useful for load testing, or for anything, for that matter.

But it was fun!  :-)

3) Configuration is tricky

Compiling the App wasn't that hard; I wound up creating a new blank Maven
project using mvn archetype:create and pasting in the POM snippets
provided in the HTMLUnit documentation.

http://htmlunit.sourceforge.net/dependencies.html

To launch my App under Selenium RC, I had to configure an extremely long
"*custom" string.  See the attached GoogleTest for an example.  Using a
batch script made Java kill the batch script but not the HTMLUnit app; the
HTMLUnit browser never dies in that case.

5) Console output / logging

If you use *custom to launch your HTMLUnit browser (as I did), you aren't
allowed to print anything to stdout or stderr, so you'll want to configure
log4j to log to a file.  The attached example does this.

6) Quitting the app

When the main method finishes, the browser stops.  I added a
Thread.sleep(MAX_VALUE) at the end of the main method to keep the browser
alive.

7) Debugging is tricky - use alert logging

Following the suggestions of others, I used alert logging to handle logs.

The trouble is that Selenium RC by default attempts to conceal those
alerts.  So, for investigation, I modified injection.html to save a copy
of window.alert in a custom variable, and then modified logToRC to just
generate an alert.  You can attach an AlertHandler to the HTMLUnit
WebClient that just logs the messages to log4j.  (I'm not including an
example of this; I think it shouldn't be necessary once you can get the
XmlHttp requests to work in the first place.)

8) Had to use the IE7 browser simulator

The FF2 browser simulator doesn't allow the user to
createEvent("HTMLEvents") and then call element.dispatchEvent.  This works
fine using the IE7 fireEvent syntax; hence the attached App simulates IE7
and not FF2.

9) It didn't seem to work running HTMLUnit in the same classloader as
Selenium Server

Hence, the separate processes.  Don't try to run GoogleTest in the same
Eclipse project as the App.  Note that we both depend on Jetty (different
versions) so that's likely to cause some trouble.

... that's all that I can remember.  :-)

Note that I don't think we can "really" support HTMLUnit as an official
browser unless somebody can come up with a good use for it.

(And by "we", I really mean "I" ... if you can't get my attachment to
work, you're really not missing much, and I don't think I'll be able to
provide much/any support.)

-Dan


[GoogleTest.java]

package com.thoughtworks.selenium;

import junit.framework.TestCase;

import org.openqa.selenium.server.SeleniumServer;
import org.openqa.selenium.server.browserlaunchers.BrowserLauncherFactory;
import org.openqa.selenium.server.mock.DummyBrowserLauncher;

public class GoogleTest extends TestCase {
    private Selenium selenium;
        private SeleniumServer server;

    public void setUp() throws Exception {
    System.setProperty("selenium.log", "selenium.log");
    server = new SeleniumServer();
                server.setProxyInjectionMode(true);
    server.start();
        String url = "http://www.google.com";
        String htmlunit = "C:\\devtools\\jdk1.5.0_12\\bin\\java.exe -classpath \"C:\\Dan\\scratch\\htmlunitselenium\\target\\test-classes;C:\\Dan\\scratch\\htmlunitselenium\\target\\classes;C:\\Documents and Settings\\dan.fabulich\\.m2\\repository\\nekohtml\\nekohtml\\0.9.5\\nekohtml-0.9.5.jar;C:\\Documents and Settings\\dan.fabulich\\.m2\\repository\\xalan\\xalan\\2.6.0\\xalan-2.6.0.jar;C:\\Documents and Settings\\dan.fabulich\\.m2\\repository\\htmlunit\\htmlunit\\1.13\\htmlunit-1.13.jar;C:\\Documents and Settings\\dan.fabulich\\.m2\\repository\\javax\\servlet\\servlet-api\\2.4\\servlet-api-2.4.jar;C:\\Documents and Settings\\dan.fabulich\\.m2\\repository\\xml-apis\\xml-apis\\1.3.02\\xml-apis-1.3.02.jar;C:\\Documents and Settings\\dan.fabulich\\.m2\\repository\\jetty\\org.mortbay.jetty\\5.1.4\\org.mortbay.jetty-5.1.4.jar;C:\\Documents and Settings\\dan.fabulich\\.m2\\repository\\commons-logging\\commons-logging\\1.1\\commons-logging-1.1.jar;C:\\Documents and Settings\\dan.fabulich\\.m2\\repository\\jdom\\jdom\\1.0\\jdom-1.0.jar;C:\\Documents and Settings\\dan.fabulich\\.m2\\repository\\rhino\\js\\1.6R5\\js-1.6R5.jar;C:\\Documents and Settings\\dan.fabulich\\.m2\\repository\\commons-httpclient\\commons-httpclient\\3.0.1\\commons-httpclient-3.0.1.jar;C:\\Documents and Settings\\dan.fabulich\\.m2\\repository\\xerces\\xercesImpl\\2.6.2\\xercesImpl-2.6.2.jar;C:\\Documents and Settings\\dan.fabulich\\.m2\\repository\\xerces\\xmlParserAPIs\\2.6.2\\xmlParserAPIs-2.6.2.jar;C:\\Documents and Settings\\dan.fabulich\\.m2\\repository\\commons-lang\\commons-lang\\2.3\\commons-lang-2.3.jar;C:\\Documents and Settings\\dan.fabulich\\.m2\\repository\\log4j\\log4j\\1.2.12\\log4j-1.2.12.jar;C:\\Documents and Settings\\dan.fabulich\\.m2\\repository\\junitperf\\junitperf\\1.8\\junitperf-1.8.jar;C:\\Documents and Settings\\dan.fabulich\\.m2\\repository\\xom\\xom\\1.0\\xom-1.0.jar;C:\\Documents and Settings\\dan.fabulich\\.m2\\repository\\gsbase\\gsbase\\2.0.1\\gsbase-2.0.1.jar;C:\\Documents and Settings\\dan.fabulich\\.m2\\repository\\avalon-framework\\avalon-framework\\4.1.3\\avalon-framework-4.1.3.jar;C:\\Documents and Settings\\dan.fabulich\\.m2\\repository\\commons-codec\\commons-codec\\1.3\\commons-codec-1.3.jar;C:\\Documents and Settings\\dan.fabulich\\.m2\\repository\\commons-io\\commons-io\\1.3.1\\commons-io-1.3.1.jar;C:\\Documents and Settings\\dan.fabulich\\.m2\\repository\\jaxen\\jaxen\\1.1.1\\jaxen-1.1.1.jar;C:\\Documents and Settings\\dan.fabulich\\.m2\\repository\\dom4j\\dom4j\\1.6.1\\dom4j-1.6.1.jar;C:\\Documents and Settings\\dan.fabulich\\.m2\\repository\\commons-collections\\commons-collections\\3.2\\commons-collections-3.2.jar;C:\\Documents and Settings\\dan.fabulich\\.m2\\repository\\com\\ibm\\icu\\icu4j\\2.6.1\\icu4j-2.6.1.jar;C:\\Documents and Settings\\dan.fabulich\\.m2\\repository\\junit\\junit\\3.8.1\\junit-3.8.1.jar;C:\\Documents and Settings\\dan.fabulich\\.m2\\repository\\logkit\\logkit\\1.0.1\\logkit-1.0.1.jar\" com.thoughtworks.selenium.App";
        selenium = new DefaultSelenium("localhost", SeleniumServer.getDefaultPort(), "*custom " + htmlunit, url);
        selenium.start();
    }

    protected void tearDown() throws Exception {
        selenium.stop();
        server.stop();
    }

    public void testGoogle() throws Throwable {
        selenium.open("http://www.google.com/webhp");

        assertEquals("Google", selenium.getTitle());
        selenium.type("q", "Selenium OpenQA");
        assertEquals("Selenium OpenQA", selenium.getValue("q"));
        selenium.click("btnG");
        selenium.waitForPageToLoad("5000");
        assertEquals("Selenium OpenQA - Google Search", selenium.getTitle());
    }

}


---------------------------------------------------------------------
To unsubscribe, e-mail: selenium-dev-unsubscribe@...
For additional commands, e-mail: selenium-dev-help@...

htmlunitselenium.zip (3K) Download Attachment
xmlextras.patch (1K) Download Attachment

Re: Freaky: Selenium RC works within HTMLUnit

by Marc Guillemot :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi Dan,

what a long Mail! ;-) I'm not wide awake this morning, therefore only a
fast answer.

- as I've already posted in HtmlUnit user list, thanks for recognizing
HtmlUnit js support quality. It has not the same meaning when such a
statement comes from "outside".

- to (1)
now fixed in HtmlUnit's SVN. Thanks for finding it.

- to (2)
- have you tried to use a custom WebConnection? This would allow you to
avoid the use of the proxy. And would surely make things much faster.
This would perhaps fix (5) and (9)

- have you tried to investigate where the time is lost?
I've tried exactly the same test with WebTest (which uses HtmlUnit as
"browser") and it took only 1.6 seconds on my computer (or 5 seconds if
you consider the report generation time too)! This time includes saving
responses to the file system too. In all cases, this is some magnitude
faster than the 25 seconds you got.

- to (8)
I'm not sure but I think that it has been fixed since 1.13

Cheers,
Marc.
--
Blog: http://mguillem.wordpress.com

Dan Fabulich wrote:

>
> HTMLUnit is a popular Java-based browser simulator with excellent
> JavaScript support.  Selenium RC is a popular in-browser testing tool
> written entirely in JavaScript.  Today I tried using the HTMLUnit
> simulated browser together with Selenium RC, running the Selenium
> JavaScript inside of the HTMLUnit browser, and it worked!  I was able to
> run/pass the GoogleTest (which simply browses to google.com and searches
> for "selenium").
>
> We don't use any of the HTMLUnit APIs for this test; instead, we do the
> whole thing in JavaScript, communicating with the simulated HTMLUnit
> browser over AJAX, just like we do with a real browser.
>
> My GoogleTest launches HTMLUnit as a separate process using *custom; the
> process's App basically does this:
>
> WebClient wc = new WebClient(BrowserVersion.INTERNET_EXPLORER_7_0,
>     "localhost", 4444);
> wc.getPage(args[0]);
>
> I've attached code that you should be able to use.
>
> Also, there's a few catches, as you might expect.
>
> 1) HTMLUnit bug 1784330 (ActiveXObject is incorrectly case sensitive).
>
> http://sourceforge.net/tracker/index.php?func=detail&aid=1784330&group_id=47038&atid=448266
>
> http://tinyurl.com/3xxkrs
>
> To workaround this, you'll need to patch xmlextras.js to refer to the
> ActiveXObject as "Msxml2.XMLHTTP" instead of "MSXML2.XmlHttp" as we do
> currently.
>
> 2) It's slow
>
> The standard Google test took 25 seconds to run; this test normally gets
> done in less than 10 seconds on my laptop.  I don't think this is going
> to be too useful for load testing, or for anything, for that matter.
>
> But it was fun!  :-)
>
> 3) Configuration is tricky
>
> Compiling the App wasn't that hard; I wound up creating a new blank
> Maven project using mvn archetype:create and pasting in the POM snippets
> provided in the HTMLUnit documentation.
>
> http://htmlunit.sourceforge.net/dependencies.html
>
> To launch my App under Selenium RC, I had to configure an extremely long
> "*custom" string.  See the attached GoogleTest for an example.  Using a
> batch script made Java kill the batch script but not the HTMLUnit app;
> the HTMLUnit browser never dies in that case.
>
> 5) Console output / logging
>
> If you use *custom to launch your HTMLUnit browser (as I did), you
> aren't allowed to print anything to stdout or stderr, so you'll want to
> configure log4j to log to a file.  The attached example does this.
>
> 6) Quitting the app
>
> When the main method finishes, the browser stops.  I added a
> Thread.sleep(MAX_VALUE) at the end of the main method to keep the
> browser alive.
>
> 7) Debugging is tricky - use alert logging
>
> Following the suggestions of others, I used alert logging to handle logs.
>
> The trouble is that Selenium RC by default attempts to conceal those
> alerts.  So, for investigation, I modified injection.html to save a copy
> of window.alert in a custom variable, and then modified logToRC to just
> generate an alert.  You can attach an AlertHandler to the HTMLUnit
> WebClient that just logs the messages to log4j.  (I'm not including an
> example of this; I think it shouldn't be necessary once you can get the
> XmlHttp requests to work in the first place.)
>
> 8) Had to use the IE7 browser simulator
>
> The FF2 browser simulator doesn't allow the user to
> createEvent("HTMLEvents") and then call element.dispatchEvent.  This
> works fine using the IE7 fireEvent syntax; hence the attached App
> simulates IE7 and not FF2.
>
> 9) It didn't seem to work running HTMLUnit in the same classloader as
> Selenium Server
>
> Hence, the separate processes.  Don't try to run GoogleTest in the same
> Eclipse project as the App.  Note that we both depend on Jetty
> (different versions) so that's likely to cause some trouble.
>
> ... that's all that I can remember.  :-)
>
> Note that I don't think we can "really" support HTMLUnit as an official
> browser unless somebody can come up with a good use for it.
>
> (And by "we", I really mean "I" ... if you can't get my attachment to
> work, you're really not missing much, and I don't think I'll be able to
> provide much/any support.)
>
> -Dan
>
>
> ------------------------------------------------------------------------
>
> package com.thoughtworks.selenium;
>
> import junit.framework.TestCase;
>
> import org.openqa.selenium.server.SeleniumServer;
> import org.openqa.selenium.server.browserlaunchers.BrowserLauncherFactory;
> import org.openqa.selenium.server.mock.DummyBrowserLauncher;
>
> public class GoogleTest extends TestCase {
>     private Selenium selenium;
> private SeleniumServer server;
>
>     public void setUp() throws Exception {
>     System.setProperty("selenium.log", "selenium.log");
>     server = new SeleniumServer();
> server.setProxyInjectionMode(true);
>     server.start();
>         String url = "http://www.google.com";
>         String htmlunit = "C:\\devtools\\jdk1.5.0_12\\bin\\java.exe -classpath \"C:\\Dan\\scratch\\htmlunitselenium\\target\\test-classes;C:\\Dan\\scratch\\htmlunitselenium\\target\\classes;C:\\Documents and Settings\\dan.fabulich\\.m2\\repository\\nekohtml\\nekohtml\\0.9.5\\nekohtml-0.9.5.jar;C:\\Documents and Settings\\dan.fabulich\\.m2\\repository\\xalan\\xalan\\2.6.0\\xalan-2.6.0.jar;C:\\Documents and Settings\\dan.fabulich\\.m2\\repository\\htmlunit\\htmlunit\\1.13\\htmlunit-1.13.jar;C:\\Documents and Settings\\dan.fabulich\\.m2\\repository\\javax\\servlet\\servlet-api\\2.4\\servlet-api-2.4.jar;C:\\Documents and Settings\\dan.fabulich\\.m2\\repository\\xml-apis\\xml-apis\\1.3.02\\xml-apis-1.3.02.jar;C:\\Documents and Settings\\dan.fabulich\\.m2\\repository\\jetty\\org.mortbay.jetty\\5.1.4\\org.mortbay.jetty-5.1.4.jar;C:\\Documents and Settings\\dan.fabulich\\.m2\\repository\\commons-logging\\commons-logging\\1.1\\commons-logging-1.1.jar;C:\\Documents and Settings\\dan.
fabulich\\.m2\\repository\\jdom\\jdom\\1.0\\jdom-1.0.jar;C:\\Documents and Settings\\dan.fabulich\\.m2\\repository\\rhino\\js\\1.6R5\\js-1.6R5.jar;C:\\Documents and Settings\\dan.fabulich\\.m2\\repository\\commons-httpclient\\commons-httpclient\\3.0.1\\commons-httpclient-3.0.1.jar;C:\\Documents and Settings\\dan.fabulich\\.m2\\repository\\xerces\\xercesImpl\\2.6.2\\xercesImpl-2.6.2.jar;C:\\Documents and Settings\\dan.fabulich\\.m2\\repository\\xerces\\xmlParserAPIs\\2.6.2\\xmlParserAPIs-2.6.2.jar;C:\\Documents and Settings\\dan.fabulich\\.m2\\repository\\commons-lang\\commons-lang\\2.3\\commons-lang-2.3.jar;C:\\Documents and Settings\\dan.fabulich\\.m2\\repository\\log4j\\log4j\\1.2.12\\log4j-1.2.12.jar;C:\\Documents and Settings\\dan.fabulich\\.m2\\repository\\junitperf\\junitperf\\1.8\\junitperf-1.8.jar;C:\\Documents and Settings\\dan.fabulich\\.m2\\repository\\xom\\xom\\1.0\\xom-1.0.jar;C:\\Documents and Settings\\dan.fabulich\\.m2\\repository\\gsbase\\gsbase\\2.0.1\\gsbas
e-2.0.1.jar;C:\\Documents and Settings\\dan.fabulich\\.m2\\repository\\avalon-framework\\avalon-framework\\4.1.3\\avalon-framework-4.1.3.jar;C:\\Documents and Settings\\dan.fabulich\\.m2\\repository\\commons-codec\\commons-codec\\1.3\\commons-codec-1.3.jar;C:\\Documents and Settings\\dan.fabulich\\.m2\\repository\\commons-io\\commons-io\\1.3.1\\commons-io-1.3.1.jar;C:\\Documents and Settings\\dan.fabulich\\.m2\\repository\\jaxen\\jaxen\\1.1.1\\jaxen-1.1.1.jar;C:\\Documents and Settings\\dan.fabulich\\.m2\\repository\\dom4j\\dom4j\\1.6.1\\dom4j-1.6.1.jar;C:\\Documents and Settings\\dan.fabulich\\.m2\\repository\\commons-collections\\commons-collections\\3.2\\commons-collections-3.2.jar;C:\\Documents and Settings\\dan.fabulich\\.m2\\repository\\com\\ibm\\icu\\icu4j\\2.6.1\\icu4j-2.6.1.jar;C:\\Documents and Settings\\dan.fabulich\\.m2\\repository\\junit\\junit\\3.8.1\\junit-3.8.1.jar;C:\\Documents and Settings\\dan.fabulich\\.m2\\repository\\logkit\\logkit\\1.0.1\\logkit-1.0.1.j
ar\" com.thoughtworks.selenium.App";

>         selenium = new DefaultSelenium("localhost", SeleniumServer.getDefaultPort(), "*custom " + htmlunit, url);
>         selenium.start();
>     }
>
>     protected void tearDown() throws Exception {
>         selenium.stop();
>         server.stop();
>     }
>
>     public void testGoogle() throws Throwable {
>         selenium.open("http://www.google.com/webhp");
>
>         assertEquals("Google", selenium.getTitle());
>         selenium.type("q", "Selenium OpenQA");
>         assertEquals("Selenium OpenQA", selenium.getValue("q"));
>         selenium.click("btnG");
>         selenium.waitForPageToLoad("5000");
>         assertEquals("Selenium OpenQA - Google Search", selenium.getTitle());
>     }
>
> }
>
>
> ------------------------------------------------------------------------
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: selenium-dev-unsubscribe@...
> For additional commands, e-mail: selenium-dev-help@...


---------------------------------------------------------------------
To unsubscribe, e-mail: selenium-dev-unsubscribe@...
For additional commands, e-mail: selenium-dev-help@...