Showing posts with label JavaScript. Show all posts
Showing posts with label JavaScript. Show all posts

2011/10/12

Java Applets - Building with Maven, Communicating with JavaScript

I have recently realized that I've not written any applet for some time and need to refresh my know-how. I hope writing it here will save some time for you if you are in similar situation.

The example will show the communication of Java Applet with Javascript in both ways -  Java-to-JS and JS-to-Java.

Building Applet with Maven

To help Maven to find applet classes and compile the applet, you need to add Java plugin dependency:
<dependency>
  <groupId>sun.plugin</groupId>
  <artifactId>plugin</artifactId>
  <version>1.6</version>
  <scope>system</scope>
  <systemPath>${java.home}/lib/plugin.jar</systemPath>
</dependency>

You'll also want to include content of your manifest file as the default genreated one does not contain Main-Class property/header:
<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-jar-plugin</artifactId>
      <configuration>
        <archive>
          <manifestFile>src/main/resources/META-INF/MANIFEST.MF</manifestFile>
        </archive>
      </configuration>
    </plugin>
  </plugins>
</build>

Example of the manifest:
Manifest-Version: 1.0
Main-Class: org.bithill.SimpleApplet

Deployment

One of things that changed significantly since writing my last applet  is an introduction of the deployment toolkit - a JavaScript library for including an applet into a web page. It looks like a marvel when compared to the tedious and error-prone applet or object tag creation and checking of the browser differences.

<script src="deployJava.js"></script>
<script>
  var attributes =
  {
    id: 'simpleApplet',
    codebase:'../../../target', // directory with the jar
    code:'org.bithill.SimpleApplet.class',
    archive:'SimpleApplet-1.0.jar',
    width: 100, height: 50,
    boxbgcolor: '#eeeeee'
  };
  var parameters = {};
  var version = '1.6';

  deployJava.runApplet(attributes, parameters, version);
</script> 
The Applet and Its Iteraction with JavaScript
package org.bithill;

import static java.lang.System.out;
import netscape.javascript.JSException;
import netscape.javascript.JSObject;
import java.applet.Applet;
import java.util.Date;

public class SimpleApplet extends Applet
{
   private JSObject js; // object for communication with JavaScript

   /** Evaluates given JavaScript expression.
    * @param jsExpression expression
    */
   public String jsEval(String jsExpression)
   {
      try { js.eval(jsExpression); }
      catch (JSException ex) { ex.printStackTrace();  }
      return new Date() + " | " + jsExpression;
   }

    /** Initializes the applet.
     *  It's called only once before the applet is started.
     */
    @Override
    public void init()
    {
       try { js = JSObject.getWindow(this);  }
       catch (JSException ex) { ex.printStackTrace();  }
    }
}

The applet gets reference to JSObject for interacting with JavaScript engine instance in the page. It is then used in jsEval() method which also return time-stamped input to demonstrate reading of the method's rerurn value. In page you need only several lines of JavaScript to connect the things together:

<script>function getAlertExpression(msg) { return "alert('" + msg + "')"; }</script>

<button onclick="document.getElementById('msgbox').innerText = ( simpleApplet.jsEval( getAlertExpression('HI') ) )">
show alert
</button>

<div id="msgbox">-- last action --</div> 

How does it work? The button has JavaScript onclick handler that calls the applet's the jsEval() method and puts its retrurn value to prepared msgbox div. Notice that applet's id is used as reference. Method jsEval() evalueates JavaScript expression in the page -that results in showing an alert dialog.

2011/06/06

Moving to Selenium 2 on WebDriver, Part No.5

Sending Mouse Clicks Via Javascript

Sometimes the WebDriver click does not work well,  after all it is still under development and bugs should be expected. For such case the ability to execute JavaScript through JavascriptExecutor comes in handy. Following code can send "click" or "dblclick" when used as eventName to a DOM element addressed by elementRef - JavaScript expression evaluating to a Node.


  public void fireJsEvent(String elementRef, String eventName)
    {

        String script =
        "" +
        " function eventFire(element, eventName)" +
        " {" +
        "  if (element.fireEvent)" +
        "  { element.fireEvent('on' + eventName); }" +
        "  else" +
        "  {" +
        "    var eventObject = document.createEvent('Events');" +    
        // parameters: type, bubbles, cancelable
        "    eventObject.initEvent(eventName, true, false);" +
        "    element.dispatchEvent(eventObject);" +
        "  }" +
        " };";

        String eventCall = String.format( "eventFire(%s, '%s');", elementRef, eventName );
        String exec = script + eventCall;
        js.executeScript(exec);
    }

Possible usage on a web page with dojo:

fireJsEvent("dojo.query('.someColumn:nth-child(1) li:nth-child(2)')[0]", "click");

2011/05/04

Moving to Selenium 2 on WebDriver, Part No.4

Conditional Waits

Majority part of web UI tests I fixed and keep fixing has the same flaw - there is either no wait for dynamically loaded parts of page or the wait is unconditional. As driver.get() is blocking this is clearly problem of an AJAX calls.

WebDriver provides two APIs for conditional waits - com.thoughtworks.selenium.Wait and org.openqa.selenium.support.ui.Wait.


Class com.thoughtworks.selenium.Wait

Simpler of the two and IMHO better suited for ad-hoc waits is this abstract class. It has only two methods - wait() and until().  You have to implement method until() and it should return true when the condition is met.  

Example of wait for pop-up of given name and switching to it:

public void waitForPopUp(final String windowName, int timeoutMs)
{
   new Wait()
   {
      @Override
      public boolean until()
      {
         try
         {
            driver.switchTo().window(windowName);
            return true;
         }
         catch (SeleniumException ignored) { }
         return false;
      }
   }.wait(String.format("Timed out waiting for %s. Waited %s",windowName, timeoutMs), timeoutMs);
}

Interfaces and classes from org.openqa.selenium.support.ui

More sophisticated approach is represented by interfaces Wait, implemented by WebDriverWait class, and  ExpectedCondition (extending com.google.common.base). Class implementing the ExpectedCondition interface must define method apply() returning true or not-null when a condition is met.

Example of wait expecting JavaScript expression evaluate to true:

int timeoutSeconds = 10;
Wait wait = new WebDriverWait(driver, timeoutSeconds);
JavascriptExecutor js = (JavascriptExecutor)driver;

public boolean waitForJsCondition(final String script, String timeoutMessage)
{
    boolean result = false;

    try
    {
        result = wait.until
        (
            new ExpectedCondition<Boolean>()
            {
               public Boolean apply(WebDriver driver)
               { return (Boolean)js.executeScript("return " +  script); }
            }
        );
    }
    catch (Throwable t)
    { handleWaitTimeout(t,timeoutMessage); }

    return result;
}

As you can see the advantage is that this Wait returns value. You can wait for an element to become visible and return it, thus keeping you code cleaner and more resilient. Even better, expected conditions returning the same type are interchangable. That not only adds to flexibility, it also helps to fight code duplication.