Minimalistic Live Testing Fable Apps With QUnit

For a while now, I have been playing around with test frameworks for Fable. Because I have used QUnit for javascript testing before, I decided to try it out, see how the workflow goes and I just LOVED it.

Basically, combine QUnit with webpack developement server to get going. QUnit has a web user-interface that shows the test results and webpack will automatically recompile and refresh the web page whenever you make changes to your tests. This way you can get feedback from your tests quickly. Just edit and save, et voilà.

Besides the web user-interface, QUnit has a cli tool to run the tests without a browser, see section: Using the QUnit CLI.

New to Fable? See the wiki to get started

Setting up QUnit

This is incredibly easy. First of all, install the simple (browser app) Fable template:

dotnet new fable

Then add this QUnit.fs gist to your project and reference the file from your .fsproj :

This QUnit.fs binding assumes there is a global QUnit variable.
<ItemGroup>
  <Compile Include="path/to/QUnit.fs" />
  <Compile Include="src/App.fs" />
</ItemGroup>

You can now use QUnit from your App.fs file. But this QUnit.fs file is just a binding for the actual library. You have to reference the QUnit library in your index.html file using a script tag (along with two div’s and a css file for the UI) as follows:

Now just fire up webpack developement server and start writing your tests, live!

dotnet fable npm-run start

Testing asynchronous code

When using async, you will run tests that might finish at some time in the future. When using QUnit, you have to tell the library when you are “finished”, here is an example:

See the official docs of QUnit to learn more

The method test.async() returns a callback of type unit -> unit that you would call to let QUnit know that your async test is done.

You can also see that the test took about 1017 milliseconds to finish which is what you would expect because there is a 1000 ms of Async.Sleep . If you don’t call finish() QUnit will contiue to run the test to check the results but the test will be considered “still running”.

If your async test has many async blocks, you have to tell QUnit how many finishing blocks it has to expect for that test, using:

let finish = test.asyncMany n

where n is the number of times you will call finish() .

Forgetting about calling finish() the right number of times is likely to happen at some point. That’s why you can set a global timeout for your tests like this:

With result:

You can provide your tests a descriptive message using test.equalWithMsg :

test.equalWithMsg result 16 "square 4 = 16"

Will result:

Using the QUnit CLI

Install it from npm:

npm install --save-dev qunitjs

On a new shell tab, build and bundle your test project once, i.e. without webpack-dev-server but rather just webpack:

dotnet fable npm-run build

add a test script to your package.json, with your bundled project (the bundle.js file) as an argument for the QUnit cli tool:

"scripts": {
  "build": "webpack -p",
  "start": "webpack-dev-server",
  "test": "qunit/qunit.js public/bundle.js"
}

Run npm run test :

The End

Simple, easy and most importantly: live. QUnit is becomming a bit old now and there many other modern test frameworks out there, but still it seems to be quite usable for your everyday testing needs. This was just me exploring what’s out there and sharing it with you. If you liked this atricle, hit that 💚 button and share!