An in-browser js_of_ocaml testing framework - js_of_ocaml integration

A unit test framework, fully compatible with
js_of_ocaml, and written with
in-browser testing of JavaScript code in mind.

Heavily influenced by oUnit.

You may find this helpful if you want to

  • test OCaml bindings to a JavaScript library

  • write tests for a JavaScript library compiled from OCaml

You could even use this library to test normal OCaml code, but in that case
you're probably better off just using oUnit for the extra features it provides.

Library contents

ocaml-webtest consists of two libraries:

  • webtest

This has no dependencies, and contains code for creating tests and suites.

  • webtest-js

This depends on js_of_ocaml, and contains code used for running tests in a

Creating test suites

ocaml-webtest supports two kinds of test cases - synchronous and asynchronous.

Both kinds of test cases can use the assertion functions assert_true,
assert_equal and assert_raises to check for expected behaviour.

Synchronous test cases are functions of type unit -> unit, and in order to
pass should return cleanly without throwing an exception.

Some examples of simple synchronous test cases:

let sync_test1 () = Webtest.Suite.assert_equal (get_five ()) 5

let sync_test2 () = Webtest.Suite.assert_true (get_value ())

let sync_test3 () = Webtest.Suite.assert_raises MyExn (exception_thrower ())

Asynchronous test cases are functions of type
((unit -> unit) -> unit) -> unit. When run they are passed a wrapper function
which must be used to wrap any asynchronous code which should be triggered as
part of the test. In order to pass, an asynchronous test case should not only
return cleanly, it should also make sure that the wrapped code runs
successfully. Asynchronous test cases can be used to check that an event handler
associated with a JavaScript object has been called.

An example of an asynchronous test case:

let async_test wrapper =
  let js_object = create_object () in

  js_object##onclose :=
    Dom_html.handler (fun _  ->
      wrapper (fun () ->
        assert_true "Object has been closed" (is_closed js_object));


If you don't need to perform any assertions in the asynchronous code but just
need to check that a handler fired, you can call the wrapper function with
Async.noop, which is just an alias for fun () -> ().

Synchronous and asynchronous test cases can be combined into suites using the
functions >::, >:~ and >::: - for example:

open Webtest.Suite

let suite =
  "suite" >::: [
    "sync_test1" >:: sync_test1;
    "sync_test2" >:: sync_test2;
    "sync_test3" >:: sync_test3;
    "async_test" >:~ async_test;

In-browser testing

Once you've created a suite, you can integrate it into an HTML document using

let () = Webtest_js.Runner.setup suite

This will create the global JavaScript object webtest which exposes a simple
API for running the test suite.

  • webtest.run is a function with no arguments - calling it will run the test

  • webtest.finished is a boolean indicating whether the suite run has finished.

  • webtest.passed is a boolean indicating whether all the tests passed.

  • webtest.log contains the log produced by running the tests.

This API can be used by browser automation tools such as
Selenium WebDriver. For an
example implementation in Python, see test_driver.py.

A "known good" setup for automating browser tests (and what this repository
uses for CI) is:

  • Firefox 50

  • Python 2.7 with version 3.3.0 of the Selenium bindings

  • geckodriver 0.15.0

  • Xvfb (optional, unless running on a headless machine)


ocaml-webtest tests itself in both OCaml
(run_tests_ocaml.ml), in JavaScript
(run_tests_browser.ml) and in Node.js

For a more real-world example, see

= version
>= "4.02.1"
>= "3.4.0"
>= "1.1"
Reverse Dependencies