Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## Unreleased

- Migrate bindings to work with ESM. NOTE: CommonJS support is removed from this
version, if you need to use CommonJS, please check previous version 0.1.1
([#12](https://github.com/melange-community/melange-jest/pull/12))

## 0.1.1 (2024-02-03)

- compatibility with melange v3
Expand Down
12 changes: 9 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,12 @@ If you need `jest-dom`, add `melange-jest.jest-dom` to the `libraries` in your `
; ...
```

## ECMAScript Modules (aka "ESM")

These bindings are only compatible with ECMAScript (ESM) modules, and not CommonJS. If you need a version that is compatible with CommonJS, please check v0.1.1.

You can refer to the [official Jest documentation](https://jestjs.io/docs/ecmascript-modules) to see how to use Jest with ESM. Note that it will require using Node with version 18 (at least), and use `node --experimental-vm-modules node_modules/jest/bin/jest.js` to run the tests.

## Usage

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](https://github.com/facebook/jest), see [the Jest documentation](https://facebook.github.io/jest/).
Expand Down Expand Up @@ -115,16 +121,16 @@ In a `dune` file:

### 2. Error `Cannot use import statement outside a module`

If you encounter the error `SyntaxError: Cannot use import statement outside a module`, it may be that you are trying to run Jest tests with `es6` files generated by Melange.
If you encounter the error `SyntaxError: Cannot use import statement outside a module`, you might be missing the `mjs` extension on the generated files.

As Melange allows to have generate both `es6` and `commonjs` outputs in the same project, to solve this issue you can add a `melange.emit` stanza that only generates `commonjs` files, for testing purposes.
As Melange allows to have generate both `es6` and `commonjs` outputs in the same project, to solve this issue you can add a `melange.emit` stanza that only generates `es6` files with `mjs` extension, for testing purposes.

In a `dune` file:

```clojure
(melange.emit
(target test)
(module_systems commonjs)
(module_systems (es6 mjs))
...
)
```
Expand Down
2 changes: 1 addition & 1 deletion dune
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@
(deps
(alias_rec test))
(action
(run npx jest)))
(run node --experimental-vm-modules %{project_root}/../../node_modules/jest/bin/jest.js)))
1 change: 1 addition & 0 deletions jest-dom/__tests__/dune
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
(target test)
(alias test)
(libraries jest jestDom melange-webapi)
(module_systems (es6 mjs))
(preprocess
(pps melange.ppx)))
2 changes: 1 addition & 1 deletion jest-dom/jestDom.ml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
let _ = [%mel.raw {|require('@testing-library/jest-dom')|}]
[%%mel.raw {|import '@testing-library/jest-dom'|}]

type expect
type t = Dom.element
Expand Down
2 changes: 1 addition & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module.exports = {
rootDir: "./_build/default/",
testMatch: ["**/*_test.js"],
testMatch: ["**/*_test.mjs"]
};

1 change: 1 addition & 0 deletions jest/__tests__/dune
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
(target test)
(alias test)
(libraries jest)
(module_systems (es6 mjs))
(preprocess
(pps melange.ppx)))
2 changes: 1 addition & 1 deletion jest/__tests__/globals_test.ml
Original file line number Diff line number Diff line change
Expand Up @@ -369,4 +369,4 @@ let () =

describe "Todo" (fun () ->
Todo.test "Todo.test";
)
)
44 changes: 23 additions & 21 deletions jest/__tests__/jest_test.ml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ open Expect
open! Expect.Operators

external setTimeout : (unit -> unit) -> int -> unit = "setTimeout"
type timers
external timers : timers = "timers" [@@mel.module]
external setImmediate : (unit -> unit) -> unit = "setImmediate"
external nextTick : (unit -> unit) -> unit = "process.nextTick"

Expand All @@ -11,85 +13,85 @@ let () =
describe "Fake Timers" (fun () ->
test "runAllTimers" (fun () ->
let flag = ref false in
Jest.useFakeTimers ();
Jest.useFakeTimers () Jest.(jest globals);
setTimeout (fun () -> flag := true) 0;
let before = !flag in
Jest.runAllTimers ();
Jest.runAllTimers () Jest.(jest globals);

expect (before, !flag) = (false, true)
);

test "runAllTicks" (fun () ->
let flag = ref false in
Jest.useFakeTimers ();
Jest.useFakeTimers () Jest.(jest globals);
nextTick (fun () -> flag := true);
let before = !flag in
Jest.runAllTicks ();
Jest.runAllTicks () Jest.(jest globals);

expect (before, !flag) = (false, true)
);

test "runAllImmediates" (fun () ->
let flag = ref false in
Jest.useFakeTimers ~config:{legacyFakeTimers=true} ();
Jest.useFakeTimers ~config:{legacyFakeTimers=true} () Jest.(jest globals);
setImmediate (fun () -> flag := true);
let before = !flag in
Jest.runAllImmediates ();
Jest.runAllImmediates () Jest.(jest globals);

expect (before, !flag) = (false, true)
);
);

test "runTimersToTime" (fun () ->
let flag = ref false in
Jest.useFakeTimers ();
Jest.useFakeTimers () Jest.(jest globals);
setTimeout (fun () -> flag := true) 1500;
let before = !flag in
Jest.advanceTimersByTime 1000;
Jest.advanceTimersByTime 1000 Jest.(jest globals);
let inbetween = !flag in
Jest.advanceTimersByTime 1000;
Jest.advanceTimersByTime 1000 Jest.(jest globals);

expect (before, inbetween, !flag) = (false, false, true)
);

test "advanceTimersByTime" (fun () ->
let flag = ref false in
Jest.useFakeTimers ();
Jest.useFakeTimers () Jest.(jest globals);
setTimeout(fun () -> flag := true) 1500;
let before = !flag in
Jest.advanceTimersByTime 1000;
Jest.advanceTimersByTime 1000 Jest.(jest globals);
let inbetween = !flag in
Jest.advanceTimersByTime 1000;
Jest.advanceTimersByTime 1000 Jest.(jest globals);

expect (before, inbetween, !flag) = (false, false, true)
);

test "runOnlyPendingTimers" (fun () ->
let count = ref 0 in
Jest.useFakeTimers ();
Jest.useFakeTimers () Jest.(jest globals);
let rec recursiveTimeout () = count := !count + 1; setTimeout recursiveTimeout 1500 in
recursiveTimeout ();
let before = !count in
Jest.runOnlyPendingTimers ();
Jest.runOnlyPendingTimers () Jest.(jest globals);
let inbetween = !count in
Jest.runOnlyPendingTimers ();
Jest.runOnlyPendingTimers () Jest.(jest globals);

expect (before, inbetween, !count) = (1, 2, 3)
);

test "clearAllTimers" (fun () ->
let flag = ref false in
Jest.useFakeTimers ();
Jest.useFakeTimers () Jest.(jest globals);
setImmediate (fun () -> flag := true);
let before = !flag in
Jest.clearAllTimers ();
Jest.runAllTimers ();
Jest.clearAllTimers () Jest.(jest globals);
Jest.runAllTimers () Jest.(jest globals);

expect (before, !flag) = (false, false)
);

testAsync "clearAllTimers" (fun finish ->
Jest.useFakeTimers ();
Jest.useRealTimers ();
Jest.useFakeTimers () Jest.(jest globals);
Jest.useRealTimers () Jest.(jest globals);
nextTick (fun () -> finish pass);
);
);
Loading