ST-JS: Strongly Typed JavaScript

Borrowing Java's syntax to write type-safe JavaScript

Reference

Writing ST-JS code

Please start by reading our What does it look like? section. It contains most of the information you need to write usual ST-JS code. On top of that, our tutorial will guide you through all the steps necessary to create and run your first ST-JS project with Maven.

If you need to use more advanced features of ST-JS, or haven't found out how a particular JavaScript construct can be expressed in Java, then keep on reading.

Special fields and methods

Most of the Java code you write will be translated basically as-is to its JavaScript counterpart. However, there are some JavaScript constructs that cannot be written as-is in Java. For these cases, ST-JS provides workarounds as special fields and methods.

All of those special fields and methods are easy to identify: there name always starts with the dollar sign ($). When you use these methods you should expect the generated JavaScript code to look slighty different (it is usually prettier, actually) than the corresponding Java construct.

Here is the list of these constructs and methods:

Collection initialization (org.stjs.javascript.JSCollections)
// JavaScript             // Java equivalent

// Create a map with the given keys and values
{k1:v1, k2:v2}            $map(k1,v1,k2,v2)

// Create an array with the given items
[a, b, c]                 $array(a, b, c)

// Convert a java array to the org.stjs.javascript.Array type
var a=b                   Array<T> a = $castArray(T[]b)
			
Associative array, maps, etc... (org.stjs.javascript.Map)
// JavaScript             // Java equivalent

// Put a key and a value in a map
x[a] = b                  x.$put(a, b)

// Retrieve a value from a map
x[a]                      x.$get(a)

// Delete an entry from a map
delete x[a]               x.$delete(a)
			
Arrays (org.stjs.javascript.Array)
// JavaScript             // Java equivalent

// Retrieve an item from an array
x[a]                      x.$get(a)

// Modify an item in an array
x[index] = val            x.$set(index, val)
			
Working with object properties (org.stjs.javascript.JsObjectAdapter)
// JavaScript             // Java equivalent

// expose all the properties of an object as a map
propsMap = obj            propsMap = $properties(obj)

// get the value of a property of an object by name
obj["prop"]               $properties(obj).$get("prop")

// convert a map as an object of a given type with the same properties
var obj = map             T obj = $object(map)

// Return the prototype of a JavaScript objects
obj.prototype             $prototype(obj)

// Return the constructor of a JavaScript object
obj.constructor           $constructor(obj)

// Replaces with the given javascriptCode (only String literals accepted).
// Use it only in extreme cases as it makes it impossible to minimize the code.
javascriptCode            $js(javascriptCode)
			
Other Javascript operations (org.stjs.javascript.Global)
// JavaScript             // Java equivalent

// Return first value the is equivalent to true in JavaScript
a || b || c               $or(a,b,c)
			

Controlling the JavaScript output

In most cases, there is no need to change the way the JavaScript is generated. There are however come cases where this is useful

ST-JS lets you customize the way the JavaScript is generated (if you want to). You can give hints to the generator by placing annotations in your Java code.

@Namespace

The annotated Class, or all the classes in the annotated package will be placed in the specified namespace. This is useful to avoid name clashes with classes coming from other libraries.

// Java with @Namespace
@Namespace("genie.in.a")
public class Bottle {
    public Bottle() {
        doSomething();
    }
}

// Java without @Namespace
public class Plain {
    public Plain() {
        doNothing();
    }
}
// JavaScript with @Namespace
stjs.ns("genie.in.a");

genie.in.a.Bottle = function() {
    doSomething();
}


// JavaScript without @Namespace

Plain = function() {
    doNothing();
}

@JavascriptFunction

All the anonymous implementations of the annotated single-method Java interface will be generated as a JavaScript anonymous function. All invocations of the method contained in the annotated interface will be generated as a direct call to that function. The interface itself will not be generated in Javascript

// Java
@JavascriptFunction
public interface EventHandler {
    public boolean onEvent(Event evt);
}

public class Something {
    public Something(Event event){
        // defining a new anonymous implementation
        EventHandler handler = (evt) -> {
			console.print(evt.name);
        };

        // calling the single-method
        handler.onEvent(event);
    }
}
// JavaScript


// the interface is not generated



Something = function(event){
    // translated as an anonymous function
    var handler = function(evt) {
        console.print(evt.name);
    };

    // invoke the function directly
    handler(event);
}

@GlobalScope

The static fields and methods in the annotated type are considered already being part of the global scope at runtime, typically provided by an existing imported JavaScript library. When a type is annotated with @GlobalScope, no corresponding JavaScript is generated.

This annotation is useful when writing bridges for an existing JavaScript library which declares some of its members in the global scope (typical example: the $ identifier for JQuery). org.stjs.javascript.Global is an example of class with this annotation, which contains the declaration of several global objects such as "window" or "console".

// Java (declaration)
@GlobalScope
public class JQuerySubset {
    public static JQuery $;
    public static JQuery $(String selector) {
        // this doesn't need to be implemented
        // the real implementation comes
        // directly from jquery.js
        throw new UnsupportedOperationException();
    }
}

// Java (usage)
import static JQuerySubset.$;

public class Something {
    public Something(){
        $(".hello").addClass(".world");
    }
}
// JavaScript (declaration)


// nothing is generated, implementation comes from
// including jquery.js







// JavaScript (usage)



Something = new function(){
    $(".hello").addClass(".world");
}

@SyntheticType

The annotated class is marked as a data-only object. Objects marked with this annotation can only contain non-private fields and cannot contain any methods. Instance of a class marked with this annotation can be initialized using the double-brace syntax in your java source code, and will be translated to a Javascript Object Literal.

This annotation is typically used by bridges to provide a correctly typed equivalent of a parameter that the javscript library expects to be an Object Literal. An example is AjaxParams used by JQuery.ajax

// Java (declaration)
@SyntheticType
public class AjaxParams {

    // some fields are omitted for brevity
    public boolean async;
    public String url;
}

// Java (usage)
import static JQuerySubset.$;

public class Something {
    public Something(){
        $.ajax(new AjaxParams(){ {
            async = false;
            url = "http://example.com";
        } });
    }
}
// JavaScript (declaration)

var AjaxParams = function(){};
stjs.extend(AjaxParams, null, [],
        function(constructor, prototype){
    prototype.async = null;
    prototype.url = null;
}, {});

// JavaScript (usage)



Something = function(){
    $.ajax({
        async : false,
        url : "http://example.com"
    });
}

@STJSBridge

The annotated package or type is marked as a simple bridge between ST-JS Java source code and an existing JavaScript library. The purpose of types annotated (or contained withing packages that are annotated) with @STJSBridge is only to provide information about types, fields and methods contained defined by an existing external JavaScript library to the Java tooling.

The JavaScript source file that contains the actual implementation that the bridge corresponds to should be specified using the sources field of @STJSBridge. By default the sources location is specified as relative to the classpath. Since ST-JS 3.2.0, the sources location can be specified using a webjar: url.

// Classpath URI
@STJSBridge( sources = {"/path/to/js/jquery.1.11.js"} ) 
public class WithClassPath {
    ...
}

// Webjar URI
@STJSBridge( sources = {"webjar:/jquery.js"} ) 
public class WithWebjar {
    ...
}

@Adapter

The static methods in the annotated type are marked as being members of another existing JavaScript type. The scope of this annotation is rather narrow, and is used by ST-JS to make it possible to use all the methods that the JavaScript standard library defines for types analog to those in the java.lang package, such as Number(and its subclasses), String, Object, etc...

ST-JS tries to keep the Java code as close as possible to the generated JavaScript code, and therefore uses java.lang.Number (and subclasses) and java.lang.String to represent the equivalent types of JavaScript. However, the member methods of each of these types are different in Java and in JavaScript. ST-JS hides this difference by providing JavaScript implementations of Java methods in stjs.js (when the Java method doesn't exist in JavaScript), and by using @Adapter Java methods corresponding to the JavaScript methods (when the JavaScript method doesn't exist in Java).

For all the methods of an adapter class, the first parameter must be object to which the method is applied. The other parameters are the parameters normally supplied to the JavaScript method.

// Java (declaration)
@Adapter
public class JSNumberAdapter {
  public static String toFixed(Number n, int p) {
    throw new UnsupportedOperationException();
  }

  public static String toPrecision(Number n, int p) {
    throw new UnsupportedOperationException();
  }
}

// Java (usage)
public class Something {
  public Something(int val){
    String fixed = JSNumberAdapter.toFixed(val, 2);
  }
}
// JavaScript (declaration)


// nothing is generated. The implementation is
// already provided by the bridged library







// JavaScript (usage)

Something = function(val){
    var fixed = val.toFixed(2);
}

@Template

this annotation can be used on a method to control how the call to this method will be generated. The parameter taken by this annotation is a name of a defined template. object.$get(i) for example will generate object.$get(i) instead of object[i]. The current list of templates:

adapter    = org.stjs.generator.writer.template.AdapterTemplate
assert     = org.stjs.generator.writer.template.AssertTemplate
array      = org.stjs.generator.writer.template.ArrayTemplate
delete     = org.stjs.generator.writer.template.DeleteTemplate
get        = org.stjs.generator.writer.template.GetTemplate
invoke     = org.stjs.generator.writer.template.InvokeTemplate
js         = org.stjs.generator.writer.template.JsTemplate
map        = org.stjs.generator.writer.template.MapTemplate
toProperty = org.stjs.generator.writer.template.MethodToPropertyTemplate
none       = org.stjs.generator.writer.template.NoneTemplate
or         = org.stjs.generator.writer.template.OrTemplate
properties = org.stjs.generator.writer.template.PropertiesTemplate
put        = org.stjs.generator.writer.template.PutTemplate
set        = org.stjs.generator.writer.template.SetTemplate
typeOf     = org.stjs.generator.writer.template.TypeOfTemplate

// Java bridge
public interface A {
    public int field; //< Illegal, oops...
    public String method();
}
// JavaScript source (bridged lib)
var A = {
    field: null,
    method: function(){}
}

As you probably know, it is impossible to place a field in an interface in Java. ST-JS provides a workaround by using the template property.

// Java bridge (declaration)
public interface A {
    /** Legal */
    @Template("toProperty")
    public int $field();
    /** Legal. Don't add, if the field is read-only*/
    @Template("toProperty")
    public void $field(int s);
    public String method();
}

// Java application code (usage)
public class App {
    public App(A a){
        a.$field(42);
        String b = a.$field();
    }
}
// JavaScript source (bridged lib)
var A = {


    field : null,


    method : function(){}
}

// Generated JavaScript application code (usage)


App = function(a){
    a.field = 42;
    var b = a.field;
}

@Native

This annotation is used to mark the constructors that are less generic when you need to overload the constructors of a class. The effect of using this annotation on a constructor or even a method is that the code of the given constructor/method is not generated at all. When you need to overload constructors, ST-JS checks that only ONE constructor has a body and all the others are marked with @Native. Also, the constructor that has the most generic signature should be left without @Native.

// Java (declaration)

public class MyClass {
	@Native
    public MyClass(){
    }
    @Native
    public MyClass(int p1){
    }
    public MyClass(Integer p1, Integer p2){
    	//do something here
    }
}

// JavaScript (declaration)

var MyClass = function(p1, p2){}; //only this constructor is generated!
stjs.extend(MyClass, null, [],
        function(constructor, prototype){
}, {});

STJS helper

The org.stjs.javascript.stjs.STJS interface is the bridge to the JavaScript code coming with the generator. It offers some helpers for different type inexistent in JavaScript:

The JavaScript and DOM bridge libraries

The JavaScript library (js-lib) is a Java library that you need as a compile-time dependency for the Java source code. This library conveniently exposes a properly typed version of the standard JavaScript library and DOM objects as defined by the browsers. The maven dependency for this library is the following:

For JavaScript and DOM the global functions and objects (like setInterval or window) are found in the org.stjs.javascript.Global class. For jQuery, the $ object and function are found in the org.stjs.javascript.jquery.GlobalJQuery class.
<dependency>
  <groupId>org.st-js.bridge</groupId>
  <artifactId>html</artifactId>
  <version>5.0.bv0</version>
</dependency>

We currently do not have a place to store the javadoc of those libraries, so for the moment, please use the documentation provided by w3schools.

ST-JS also comes with another Java library that allows you to share objects easily between your client (JavaScript) app and you server (Java) by providing concrete java implementations of some of the classes in the org.stjs.javascript package (such as Array and Map). The maven dependency for this library is the following

<dependency>
  <groupId>org.st-js</groupId>
  <artifactId>server</artifactId>
  <version>${stjs.version}</version>
</dependency>

This dependency allows you to create maps and arrays and to serialize them (as JSON for example).

JavaScript library bridges

As we have mentionned before, STJS is NOT a web framework, so no visual components or other components are bundled with STJS. You should therefore rely on existing components defined by other JavaScript frameworks like jQuery, DOJO, etc. There are two different ways integrate STJS-generated code with existing JavaScript libraries:

By writing parts of your application in JavaScript, and using the existing library and directly calling the generated STJS code. While you can probably make do with this for a while, this is not the recommended technique.

By writing all your application in ST-JS enabled Java, by writing a Java bridge for the JavaScript library. This is the recommended approach, and will allow you to take advantage of all the benefits and tooling of Java, while still using your favorite, cross-browser library.

STJS already provides bridges for jQuery and jQuery UI plugins. The bridge is composed mostly of Java interfaces that have the same name as their JavaScript counterpart. Sometimes you may also need to provide global objects or functions (that will be implemented as static fields or methods of the object). In the case of a static method, the method should throw UnsupportedOperationException - to indicate it's a method to be used in the JavaScript code (not in some server-side Java code).

One interesting feature of the bridges is that they are not submitted to the same list of constrains as the regular STJS Java code. This means that you can overload methods in order to provide more clarity to the user. A good example is the way plugins are built in jQuery where the same function (usually the plugin's name) has many different usages: activate the plugin, change an option, get a state value, call a method, etc.

The JQuery bridge must be added as a compile time dependency to your project. Here is the maven dependency section for this artifact.

We currently do not have a place to store the javadoc for the jQuery and jQuery UI bridges, so for the moment please use the documentation provided by jQuery and jQuery UI

<dependency>
  <groupId>org.st-js.bridge</groupId>
  <artifactId>jqueryui</artifactId>
  <version>1.10.3.bv0</version>
</dependency>

Maven Plugin - the JavaScript Generator

This is the STJS module that will actually take your both Java source code and the corresponding compiled classes, and generate the corresponding JavaScript code that your browser can execute. This module can be used either on the command line, or as a maven plugin.

To use the command line version of the module, please send us an email to ask us to write the documentation for it...

To use the generator as a maven plugin, include the following snippet in your pom.xml

<plugin>
  <groupId>org.st-js</groupId>
  <artifactId>stjs-maven-plugin</artifactId>
  <version>${stjs.version}</version>
  <executions>
    <execution>
      <id>main</id>
      <goals>
        <goal>generate</goal>
      </goals>
    </execution>
    <!-- if you use the JUnit runner -->
    <execution>
      <id>test</id>
      <goals>
        <goal>generate-test</goal>
      </goals>
    </execution>
  </executions>
  <configuration>
    <includes>
       <include>**/*.java</include>
    </includes>
  </configuration>
</plugin>

Configuration

You can activate separately the JavaScript generation for main sources and tests. Here are the goals of the maven plugin:

There are some parameters that can be used to configure the plugin:

Maven configuration for auto-generation in Eclipse

If you use Eclipse you can take advantage of the Maven / Eclipse integration. The Javascript code is generated each time the corresponding Java class is modified and saved. This way any modification you bring to your code will be instantly observed on the browser! Note: you need the at least the 1.0 version of the Eclipse plugin for Maven.

<plugin>
  <groupId>org.eclipse.m2e</groupId>
  <artifactId>lifecycle-mapping</artifactId>
  <version>1.0.0</version>
  <configuration>
    <lifecycleMappingMetadata>
      <pluginExecutions>
        <pluginExecution>
          <pluginExecutionFilter>
            <groupId>org.st-js</groupId>
            <artifactId>
              stjs-maven-plugin
            </artifactId>
            <versionRange>
              [${stjs.version},)
            </versionRange>
            <goals>
              <goal>generate</goal>
              <!-- if you use the test helper -->
              <goal>generate-test</goal>
            </goals>
          </pluginExecutionFilter>
          <action>
             <execute>	
                 <runOnIncremental>true</runOnIncremental>
             </execute>
          </action>
        </pluginExecution>
      </pluginExecutions>
    </lifecycleMappingMetadata>
  </configuration>
</plugin>

The JUnit runner

Using STJSTestDriverRunner to execute JavaScript unit tests in a browser

The ST-JS JUnit runner module allows you to write your unit tests in ST-JS enabled Java, have JUnit run them on a browser of your choice (or multiple browsers in parallel) and report the test results.

In order to use the STJS JUnit runner, you must first make sure it is included in your test classpath. If you are using maven, you can simply add the following dependency to your pom.xml

<dependency>
  <groupId>org.st-js</groupId>
  <artifactId>test-helper</artifactId>
  <version>${stjs.version}</version>
  <scope>test</scope>
</dependency>

To activate the STJS JUnit runner, annotate your JUnit test classes this way

import org.stjs.testing.driver.STJSTestDriverRunner;
import org.junit.annotations.Test;

@RunWith(STJSTestDriverRunner.class)
public class TestMyStuff {

    @Test
    public void testMyThing(){
        // Your test code goes here
    }
}

This is all you need to get your unit tests to execute in your system's default browser. While writing your unit tests, you can of course use the main JUnit annotations such as @Test, @Before and @After

Customizing the way the unit tests run

In order to run your unit tests in a browser, the STJS Junit runner builds an HTML page that includes all the necessary HTML and javascript to execute your tests and return the result to JUnit. By default, the HTML page that is sent to the browser includes the following things:

You can have a better control on what is sent in that HTML page by using some annotations defined by STJS.

@HtmlFixture

This optional annotation can be applied to your test class to force the STJSTestDriverRunner to include a specific HTML fragment on the page it sends to the browser. This is useful if the piece of code you are unit testing does some DOM manipulation and needs some DOM elements to be present to function as expected.

If the HTML fragment is short enough, it can be specified verbatim in the annotation.

@RunWith(STJSTestDriverRunner.class)
@HtmlFixture("<div id='importantContainer'></div>")
public class TestSimpleFixture {
    ...
}

If the fragment is longer, the annotation allows you to specify a path to a classpath resource that contains the HTML code. The HTML fragment file will be looked up using ClassLoader.getResourceAsStream(). This means that STJSTestDriverRunner (trough the ClassLoader) will first attempt to find the file in your classpath. If the file cannot be found in your classpath, then STJSTestDriverRunner will look for the file starting at the "document root" or your webapp, if any. For a typical maven project, this means it will first look in /target/WEB-INF/classes, and then in /target.

@RunWith(STJSTestDriverRunner.class)
@HtmlFixture(url = "/SomeComplexHtmlFragment.html")
public class TestSimpleFixture {
	...
}
@ScriptsBefore and @ScriptsAfter

These optional annotations can be applied to your test class to force the STJSTestDriverRunner to include extra javascript files in the <head> section of the HTML page that is sent to the browser. This is useful when you are using a bridged JavaScript library that depends on a third party (unbridged) library, and that the unit tests require this library to be in the JavaScript execution environment.

Script files specified in @ScriptsBefore will be included in the HTML page before the class under test and all its dependencies. Script files specifed in @ScriptsAfter will be included in the HTML page after the class under test and all its dependencies.

Each of the strings passed as a value to these annotations will be used verbatim in the generated HTML. This means that you can pass either a path to a javascript file that exists within your project, or one that resides on another domain.

@RunWith(STJSTestDriverRunner.class)
@ScriptsBefore({"/someLibBefore.js"})
@ScriptsAfter({"http://example.com/someLibAfter.js"})
public class TestHelloWorld {
	...
}

Will generate the following fragment of HTML

<head>
  <!-- contents of @ScriptsBefore -->
  <script src="/someLibBefore.js" type="text/javascript"></script>

  <!-- Class under test plus other stuff required by stjs  -->
  <script src="/stjs.js" type="text/javascript"></script>
  <script src="/HelloWorld.js" type="text/javascript"></script>

  <!-- contents of @ScriptsAfter -->
  <script src="http://example.com/someLibAfter.js" type="text/javascript"></script>
</head>

If the script passed to this annotation is a reference to a file defined in your project (ie: it doesn't start with a protocol handler such as http:, file:, ftp:, https:, etc...), then the script file will be looked up using ClassLoader.getResourceAsStream(). This means that STJSTestDriverRunner (trough the ClassLoader) will first attempt to find the file in your class path. If the file cannot be found in your classpath, then STJSTestDriverRunner will look for the file starting at the "document root" or your webapp, if any. For a typical maven project, this means it will first look in /target/WEB-INF/classes, and then in /target.

Configuring the JUnit runner

Basic configuration

You can configure some of the test driver's parameters in a file called stjs-test.properties that must be placed the root of your class path. The properties supported by this file are the described in the table below

All these properties can be overridden by specifying them as system properties when launching the java vm. For example to force debug mode when launching the tests via Maven you can run `mvn test -Dstjs.test.debug=true`.

Property Description
stjs.test.config The classpath location of properties file that contains the stjs test driver configuration. Default value is "/stjs-test.properties"
stjs.test.browsers A comma separated list of browsers on which to run the tests. A test is successful only if it has been run successfully on all the browsers in this list. See the table below for a description of the supported browsers. The default value is "desktopDefault".
stjs.test.port the port opened by the test driver waiting for connection from the browsers. Default value is 8055
stjs.test.wait the time (in seconds) the test driver waits for the number of configured browsers to connect. Default value is 10
stjs.test.skipIfNoBrowser if this is true, if no browser was connected that it considers the tests as ignored (can be used in some batch processing, without failing completely the tests). Default value is false
stjs.test.startBrowser if true, if after 2 seconds (normally check of the client's code check is 1 second) no browser connected to the test driver, it tries to start the system's default browser. This can only work is the Desktop.isDesktopSupported() check return true (so usually a developer's machine). Default value is true
stjs.test.testTimeout the time (in seconds) the test driver waits for a test to return a result from the browser. Passed this time the test is considered failed. Default value is 2 seconds
stjs.test.debug if this is true, debug information is displayed. Default value is false
stjs.test.debugJavaScript if true, JUnit tests are run in JavaScript debug mode, where ST-JS gives the opportunity to the developper to manually set JS breakpoints in his browser before the unit test are launched. If this property is not set, ST-JS automatically attempts to detect if the JUnit tests are run from an IDE in debug mode and will activate the JavaScript debug mode if that is the case. Default value is unset (ie: autodetect)
firefox.bin the path to the binary of firefox (see "firefox" in the table below)
chrome.bin the path to the binary of Google Chrome or chromium (see "chrome" in the table below)
phantomjs.bin the path to the binary of phantomjs (see "phantomjs" in the table below)
stjs.test.browsers values: Browsers that require a graphics system

The browsers described in the table below can only run on operating systems that provide some kind of graphics sub-system. Fox example, these browsers won't work if your operating system is a Linux distribution without a running X server.

Value Description
desktopDefault

Launches whichever browser is the default for the desktop on which the tests are running.

On windows the browser is launched using Desktop.getDesktop().browse(). On other systems it is launched using the "xdg-open" utility. This browser might fail to launch on headless machines in some operating systems, for example a linux server without an X11 server.

firefox

Launches firefox.

STJS will look in the common firefox installation directories to find the binary. If firefox is not installed in the standard location on your target system, you can specify the path of the binary in the firefox.bin property in "stjs-test.properties", in whichever file you specified in the stjs.test.config system property or on the command line.

chrome

Launches Goole Chrome (or chromium).

STJS will look in the common chrome installation directories to find the binary. If chrome is not installed in the standard location on your target system, you can specify the path of the binary in the chrome.bin property in "stjs-test.properties", in whichever file you specified in the stjs.test.config system property or on the command line.

stjs.test.browsers values: Browsers that can run on headless systems

Use one of these browsers if your test execution environment doesn't provide a working graphics subsystem (such as a running X server for Linux).

Value Description
rhino

Runs the tests in an instance of Rhino that is embedded in stjs' test runner.

No additional software needs to be installed on the target system for this browser to run.

remote

Doesn't launch any browsers.

It assumes that a browser is already running somewhere (potentially on a remote machine), and that this browsers periodically polls the stjs test runners HTTP port to fetch unit tests to run.

phantomjs

Launches all the tests in phantomjs.

Phantomjs is a lightweight, headless browser based on webkit and V8. Phantomjs needs to be installed on the target system for this browser to run.

STJS will look in the common phantomjs installation directories to find the binary. If phantomjs is not installed in the standard location on your target system, you can specify the path of the binary in the phantomjs.bin property in "stjs-test.properties", in whichever file you specified in the stjs.test.config system property or on the command line.

headlessFirefox

Only supported on systems that use an X11 server.

This browser needs Xvfb and firefox to be installed on the target system. Xvfb (X Virutal Frame Buffer) is an X11 server that doesn't need any real graphics capability to run, and will happily run on servers that do not have a graphics card.

This browser will first launch an instance of Xvfb, and then launch a firefox instance instructing it to use Xvfb as its display.

Xvfb is expcted to be in your PATH. The path to the firefox binary can be configured in the same way as for the "firefox" browser.

headlessChrome Same as headlessFirefox but starts Google Chrome instead.

Gradle Plugin

Thanks to Daniel you can now use ST-JS also with Gradle. You can find the plugin's sources here.

Fork me on GitHub