BuckleScript bindings for Jest
NOTE: NPM package has moved to @glennsl/bs-jest
. Remember to update both package.json
AND bsconfig.json
.
Most of what's commonly used is very stable. But the more js-y parts should be considered experimental, such as mocking and some of the expects that don't transfer well, or just don't make sense for testing idiomatic Reason/OCaml code but could be useful for testing js interop.
- Global: Fully implemented and tested, apart from
require.*
- Expect: Mostly implemented. Functionality that makes sense only for JS interop have been moved to
ExpectJs
. Some functionality does not make sense in a typed language, or is not possible to implement sensibly in ML. - Mock Functions: Experimental and unsafe implementation, very much in flux. The Jest bindings will most likely be relegated to the
MockJs
module as it's very quirky to use with native code. A separate native from-scratch implementation might suddenly appear asMock
. - The Jest Object: Fake timers are fully implemented and tested. Mock functionality has been moved to
JestJs
. It's mostly implemented, but experimental and largely untested. - Snapshotting: Expect functions exist and work, but there's currently no way to implement custom snapshot serializers.
open Jest;
describe("Expect", () => {
open Expect;
test("toBe", () =>
expect(1 + 2) |> toBe(3))
});
describe("Expect.Operators", () => {
open Expect;
open! Expect.Operators;
test("==", () =>
expect(1 + 2) === 3)
}
);
See the tests for more examples.
npm install --save-dev @glennsl/bs-jest
Then add @glennsl/bs-jest
to bs-dev-dependencies
in your bsconfig.json
:
{
...
"bs-dev-dependencies": ["@glennsl/bs-jest"]
}
Then add __tests__
to sources
in your bsconfig.json
:
"sources": [
{
"dir": "src"
},
{
"dir": "__tests__",
"type": "dev"
}
]
Put tests in a __tests__
directory and use the suffix *test.ml
/*test.re
(Make sure to use valid module names. e.g. <name>_test.re
is valid while <name>.test.re
is not). When compiled they will be put in a __tests__
directory under lib
, with a *test.js
suffix, ready to be picked up when you run jest
. If you're not already familiar with Jest, see the Jest documentation.
One very important difference from Jest is that assertions are not imperative. That is, expect(1 + 2) |> toBe(3)
, for example, will not "execute" the assertion then and there. It will instead return an assertion
value which must be returned from the test function. Only after the test function has completed will the returned assertion be checked. Any other assertions will be ignored, but unless you explicitly ignore them, it will produce compiler warnings about unused values. This means there can be at most one assertion per test. But it also means there must be at least one assertion per test. You can't forget an assertion in a branch, and think the test passes when in fact it doesn't even test anything. It will also force you to write simple tests that are easy to understand and refactor, and will give you more information about what's wrong when something does go wrong.
At first sight this may still seem very limiting, and if you write very imperative code it really is, but I'd argue the real problem then is the imperative code. There are however some workarounds that can alleviate this:
- Compare multiple values by wrapping them in a tuple:
expect((this, that)) |> toBe((3, 4))
- Use the
testAll
function to generate tests based on a list of data - Use
describe
and/orbeforeAll
to do setup for a group of tests. Code written in OCaml/Reason is immutable by default. Take advantage of it. - Write a helper function if you find yourself repeating code. That's what functions are for, after all. You can even write a helper function to generate tests.
- If you're still struggling, make an issue on GitHub or bring it up in Discord. We'll either figure out a good way to do it with what we already have, or realize that something actually is missing and add it.
For the moment, please refer to Jest.mli.
- bs-jest-dom - Custom matchers to test the state of the DOM
If you encounter the error SyntaxError: Cannot use import statement outside a module
, it may be that you are mixing es6
and commonjs
modules in your project. For example, this can happen when you are building a React project since React builds are always in ES6. To fix this, please do the following:
- Make sure your
bsconfig.json
compiles"es6"
or"es6-global"
:
"package-specs": {
"module": "es6",
}
- Install esbuild-jest through
yarn
ornpm
as adevDependency
. - Build your Rescript project with deps:
rescript build -with-deps
. - Add this to your Jest config (or
jest
of yourpackage.json
):
{
"transform": {
"^.+\\.jsx?$": "esbuild-jest"
},
"transformIgnorePatterns": ["<rootDir>/node_modules/(?!(rescript|@glennsl/bs-jest)/)"]
}
- The property
"transformIgnorePatterns"
is an array of strings. Either you do some regex or organize them in an array. Please make sure all folders innode_modules
involving compiled .res/.ml/.re files and the like such asrescript
or@glennsl/bs-jest
are mentioned in the aforementioned array.
This problem is also addressed in Issue #63.
git clone https://github.com/glennsl/bs-jest.git
cd bs-jest
npm install
Then build and run tests with npm test
, start watchers for bsb
and jest
with npm run watch:bsb
and npm run watch:jest
respectively. Install screen
to be able to use npm run watch:screen
to run both watchers in a single terminal window.
- [BREAKING] Actually removed
toThrowException
,toThrowMessage
andtoThrowMessageRe
as they relied on assumptions about BuckleScript internals that no longer hold.
- Added
Expect.toContainEqual
- Updated to Jest 26.5.2
- Upgraded bs-platform to 8.3.1
- Added
Expect.toMatchInlineSnapshot
- Updated to Jest 25.1.0
- Added
Todo.test
- Updated jest to 24.3.1
- Fixed jest warnings not to return anything from
describe
callbacks by explicitly returningundefined
(otherwise BuckleScript will return something else like()
, which is represented as0
) - Fixed several newly uncovered uncurrying issues caused by surprise breaking changes in BuckleScript (Thanks again, Bob!)
- Added
Jest.advanceTimersByTime
, which is basically just an alias ofJest.runTimersToTime
- Added
Expect.not__
for transitional compatibility with Reason syntax change of "unkeywording"not
by mangling it intonot_
, andnot_
intonot__
and so on.
- Made uncurrying explicit for
afterAllPromise
too.
- Made uncurrying explicit to fix a breaking change in implicit uncurrying from
bs-platform
4.0.7 (Thanks Bob!)
- Removed some optimizations on skipped tests that Jest 23 suddenly started objecting to (#30)
- Added
MockJs.new0
,new1
andnew2
- Added
timeout
argument totestAsync
andtestPromise
functions - Added
beforeEachAsync
,beforeEachPromise
,afterEachAsync
andafterEachPromise
- Added
beforeAllAsync
,beforeAllPromise
,afterAllAsync
andafterAllPromise
- Moved repository from
reasonml-community/bs-jest
toglennsl/bs-jest
- Renamed NPM package from
bs-jest
to@glennsl/bs-jest
- Added
toThrowException
- Fixed an issue with custom Runner implementation shadowing the global
test
function from jest - Fixed a typo in the js boundary of
not_ |> toBeLessThanEqual
- Removed deprecations
- Added
testAll
,Only.testAll
,Skip.testAll
that generates tests from a list of inputs - Fixed type signature of
fail
- Added
expectFn