Unit tests with Rescript 9 and ES6 modules (again)

Testing with bs-jest is a common topic here. I use bs-jest to test Ratoon’s marketing portal. This week, I upgraded from bs-platform 8 to rescript 9.1.4, Next.js 11.1.2 and React 17.0.2. I also switched from commonJS to ES6 Mostly the upgrade went smoothly, but I had problems with tests. Initially, these were the usual problems I have read about here. I resolved all of these by updating the jest config to match files with the ‘.mjs’ extension. I also added rules to transform these and specific node_module subfolders including @glennsl/bs-jest, @testing-library/react, bs-dom-testing-library and rescript. Still, tests failed with the error message:

TypeError: React.createElement is not a function

This was coming from Rescript 9 generated JavaScript. I did several checks to ensure I was not using mis-matched versions of react, jest, rescript, … I reread the ES2015 module specification and tried porting @reascriptbr/react-testing-library to Rescript 9 and ES6 modules. I had the same problem every time.

Finally, I tried modifying the generated code. I found that if I changed the generated

import * as React from “react”;

to

import React from “react”;

or

import {default as React" from "react";

all the tests pass.

I’m not sure if this is an issue with babel-jest or the Rescript code generator. When using Rescript to generate commonJS, the generator emits

var React = require("react");

implying to me that JavaScript will treat the React variable as an object rather than the namespace that is implied by

import * as React from "react";

Has anyone else run into this situation. Alternatively, do any of the maintainers have recommendations for react-testing. I have seen Dusty Philip’s blog on Zora testing. Is Zora preferred over Jest?

Below is configuration I borrowed from @rescriptbr/react-testing-library to simplify and explore. If there is interest, I’ll set up a playground.

bsconfig.json

Blockquote
{
“name”: “bs-react-testing-library”,
“bsc-flags”: ["-bs-no-version-header", “-bs-super-errors”],
“warnings”: {
“number”: “+A-48-42-103”,
“error”: “+A-3-44-10”
},
“reason”: {
“react-jsx”: 3
},
“refmt”: 3,
“package-specs”: {
“module”: “es6”,
“in-source”: true
},
“suffix”: “mjs”,
“bs-dependencies”: [“bs-dom-testing-library”, “@rescript/react”],
“bs-dev-dependencies”: ["@glennsl/bs-jest"],
“sources”: [
{
“dir”: “src”,
“subdirs”: [
{
“dir”: “tests”,
“type”: “dev”
}
]
}
]
}
block quote

package.json

block quote
{
“name”: “@rescriptbr/testing-library”,
“version”: “1.0.0”,
“description”: “ReScript bindings for react-testing-library”,
“repository”: “rescriptbr/react-testing-library”,
“author”: {
“name”: “ReScript Brasil”,
“email”: “vmarcosp.pereira@gmail.com
},
“license”: “MIT”,
“files”: [
“src/.res",
"src/
.resi”,
“bsconfig.json”
],
“scripts”: {
“build”: “rescript build”,
“clean”: “run-p clean:*”,
“clean:bsb”: “rescript clean”,
“jest”: “jest”,
“pretest”: “yarn build”,
“test”: “yarn jest”
},
“keywords”: [
“rescript-react”,
“rescript-react-testing-library”
],
“devDependencies”: {
@babel/core”: “^7.15.5”,
@babel/node”: “^7.15.4”,
@babel/preset-env”: “^7.15.6”,
@babel/preset-react”: “^7.14.5”,
@glennsl/bs-jest”: “^0.7.0”,
@rescript/react”: “^0.10.3”,
@sheerun/mutationobserver-shim”: “^0.3.3”,
@testing-library/react”: “^12.1.1”,
“babel-jest”: “^27.2.4”,
“bs-dom-testing-library”: “^0.7.0”,
“jest”: “^27.2.4”,
“npm-run-all”: “^4.1.5”,
“rescript”: “^9.1.4”
},
“dependencies”: {
“next”: “^11.1.2”,
“react”: “17.0.2”,
“react-dom”: “17.0.2”
}
}
blockquote
babel.config.js
module.exports = {
“presets”: [
“next/babel”
],
“plugins”: [ ]
}
blockquote

and jest.config.js

blockquote
module.exports = {
clearMocks: true,
moduleFileExtensions: [
“js”,
“mjs”,
],
setupFilesAfterEnv: [
“./setupTests.js”
],
testEnvironment: “jsdom”,
testMatch: [
/tests//.mjs",
"/tests//
.bs.js”,
],
transform: {
“^.+.m?js$”: “babel-jest”,
},
transformation
transformIgnorePatterns: [
“node_modules/(?!(@glennsl/bs-jest|@testing-library/react|bs-dom-testing-library|rescript)/)”
],
verbose: true,
};
block quote

1 Like

Truly the worst. Such an unpleasant thing to deal with.

My current recipe:
I ended up letting jest be magically global and wrote my own bindings to call in to them.:
@val external describe: (string, () => ()) => () = "describe"

test files are along side their sources.

used Parcel 2.0.0-rc.0 to bundle:
parcel build --no-optimize --no-scope-hoist src/**/*.test.bs.js

add dist to jest config testMatch: '**/dist/*.test.bs.js'

run jest

good luck!

1 Like

@stephanie If you don’t need the entire library this Jest solution might be of interest. It uses a minimal set of bindings and you can simply just add any bindings you need.
https://forum.rescript-lang.org/t/unit-testing-with-jest/2323

Thanks @mouton. for this great suggestion. I note you are using the bs.js extension rather than .mjs. Have you set package-specs.module to “es6” or are you using “commonjs”? Most of the discussion on this topic is focused on bs-platform 8.x rather than rescript 9.1.x. Are you using rescript 9?

Thank you @kay-tee. In order to simplify, I switched from Ratoon’s Next.js marketing portal and ported a set of test bindings (@rescriptbr/rescript-testing-library) Ratoon uses from bs-platform 8.x to rescript 9. Using bcc -format, it was easy to convert the code though I needed to also convert deprecated use of @bs.send.pipe to @send syntax - again not too much effort and I now have a reasonably complete set of Jest bindings for React that I will give back to @rescriptbr as soon as I resolve this last remaining issue. Essentially, I have down something similar to your suggestion but for a broader set of the API.

As @ryyppy has already ported his Next.js starter to ES6 module, I’m going to look at what rescript is generating for him. If it’s the same, this may be a problem with babel/bs-jest rather than rescript.

I appreciate your response.

@Stef

rescript 9.
I just changed our project to type: “module” but I don’t know that it helped much of anything. The inconsistency of endings and module patterns extends into node_modules as far as I could tell and I couldn’t see any resolution in sight.

I asked Dusty about his zora config and he didnt offer any better solution to this pain so It wasnt an improvement in my experience. I tried Zora, and Avajs also.

A

I am interested in getting a similar setup working, except using vitejs instead of next, and focused on an SPA context.

I will try to experiment in a few weeks and report back my results.

In my experiments in simply trying bs-jest, jest, rescript, and es6 output, I noticed that I needed to use jest 26.x with bs-jest.

I haven’t tried any of the bucklescript/rescript wrappers for react testing-library yet.