Git Product home page Git Product logo

ocaml-webtest's Introduction

ocaml-webtest

Build status API reference

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 browser.

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));
      Js._false);

  js_object##close

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 Webtest_js.Runner.setup:

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 suite.
  • 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 is:

  • Firefox 89
  • Python 3.8.5 with version 3.141.0 of the Selenium bindings
  • geckodriver 0.29.1
  • Xvfb (optional, unless running on a headless machine)

Examples

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

For a more real-world example, see ocaml-webaudio.

ocaml-webtest's People

Contributors

dboris avatar johnelse avatar little-arhat avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

ocaml-webtest's Issues

Improve README

  • Synchronous test usage
  • Asynchronous test usage
  • Javascript API and Selenium integration

Improve async test behaviour on failure

An async test could potentially throw an exception after setting up whatever events are needed to call its callback. This will lead to the callback being called, but the test infrastructure will also handle a failure or error.

It's fairly easy to avoid this by not doing anything in the test after setting up the callback, but the infrastructure should handle this.

Handle errors/failures resulting from the async part of an async test case

Errors thrown in code meant to be run asynchronously may prevent the callback from being called. assert_* cannot be used in the asynchronous code for the same reason.

One option would be to provide a wrapper function which will wrap all the asynchronous code, and handle any errors.

For example

let async_test async_wrapper =
  let js_object = create_object () in

  js_object##onclose :=
    Dom_html.handler (fun _  ->
      async_wrapper (fun () ->
        assert_equal (js_object##state) (Js.string "closed"));
      Js._false);

  js_object##close

async_wrapper would handle errors/failure (if applicable), record the test result and then continue with the rest of the tests.

Improve logging

When running tests in a browser, all the logs are extracted in one chunk after all tests have run.

The logs should be added to while the tests run, and polled periodically by the selenium script.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.