Giter Site home page Giter Site logo

rescript-test's Introduction

ReScriptTest

A lightweight test framework for ReScript

Screen Shot 2021-04-04 at 19 58 39

Check out the documentation!

Installation

Run the following in your console:

$ yarn add --dev rescript-test

Then add rescript-test to your bsconfig.json's bs-dev-dependencies:

 {
   "bs-dev-dependencies": [
+    "rescript-test",
   ]
 }

Usage

$ # All tests
$ retest 'test/**/*.bs.js'
$ # Single file
$ retest 'test/MyTest.bs.js'

Testing with DOM

The test framework can simulate a browser using JSDOM, to activate it, simply add the --with-dom option.

$ # All tests
$ retest --with-dom 'test/**/*.bs.js'
$ # Single file
$ retest --with-dom 'test/MyTest.bs.js'

Basics

open Test

let intEqual = (~message=?, a: int, b: int) =>
  assertion(~message?, ~operator="intEqual", (a, b) => a === b, a, b)

let stringEqual = (~message=?, a: string, b: string) =>
  assertion(~message?, ~operator="stringEqual", (a, b) => a == b, a, b)

test("Equals", () => {
  let a = 1
  let b = 1
  intEqual(a, b)
})

let isCharCode = (a, b) => {
  a->String.charCodeAt(0) === b
}

test("Custom comparator", () => {
  let a = "a"

  assertion(~message="Char code should match", ~operator="isCharCode", isCharCode, a, 97.0)
  assertion(~message="Char code should match", ~operator="isCharCode", isCharCode, a, 98.0)
})

type user = {username: string, id: string}

let userEq = (a, b) => a.id === b.id
let userEqual = (~message=?, a: user, b: user) =>
  assertion(~message?, ~operator="userEqual", userEq, a, b)

test("DeepEquals", () => {
  let a = {username: "user", id: "a"}
  let b = {username: "user", id: "a"}
  stringEqual(a.username, b.username)
  userEqual(a, b)
})

Outputs:

1/4: Equals
  PASS - No message
2/4: Custom comparator
  PASS - Char code should match
  FAIL - Char code should match
    ---
    operator: isCharCode
    left:  a
    right: 98
    ...
3/4: DeepEquals
  PASS - No message
  PASS - No message
4/4: Async
  PASS - No message

# Ran 4 tests (6 assertions)
# 3 passed
# 1 failed

API

Tests

  • test(name, body)
  • createTestWith(~setup: unit => 'a, ~teardown: 'a => unit=? -> test
  • testAsync(name, body)
  • createTestAsyncWith(~setup: unit => 'a, ~teardown: 'a => unit=?, name, body: ('a, cb) => unit) -> testAsync

Operators

  • throws(func, ~message: string=?, ~test: exn => bool=?)
  • doesNotThrow(func, ~message: string=?)
  • assertion(comparator, a, b, ~operator: string=?, ~message: string=?)
  • pass()
  • fail()
  • todo(string)

Creating assertion shorthands

let stringMapEqual = (~message=?, a, b) =>
  assertion(
    ~message?,
    ~operator="stringMapEqual",
    (a, b) => Belt.Map.String.eq(a, b, (a, b) => a === b),
    a,
    b,
  )
Generic equal/deepEqual (not recommended)

Those that be useful to transition from an existing testing library, but we do not recommend polymorphic checks.

let equal = (~message=?, a, b) => assertion(~message?, ~operator="equal", (a, b) => a === b, a, b)

let deepEqual = (~message=?, a, b) =>
assertion(~message?, ~operator="deepEqual", (a, b) => a == b, a, b)

Create tests with setup and teardown

The setup function returns a clean context for the test, the teardown function resets it.

let testWithRef = createTestWith(~setup=() => ref(0), ~teardown=someRef => someRef := 0)

testWithRef("Setup & teardown", someRef => {
  incr(someRef)
  equal(someRef.contents, 1)
})

If you want to test with React, you can add the following helper as your test utility file:

@bs.val external window: {..} = "window"
@bs.send external remove: Dom.element => unit = "remove"

let createContainer = () => {
  let containerElement: Dom.element = window["document"]["createElement"]("div")
  let _ = window["document"]["body"]["appendChild"](containerElement)
  containerElement
}

let cleanupContainer = container => {
  ReactDOM.unmountComponentAtNode(container)
  remove(container)
}

let testWithReact = createTestWith(~setup=createContainer, ~teardown=cleanupContainer)
let testAsyncWithReact = createTestAsyncWith(~setup=createContainer, ~teardown=cleanupContainer)

And then use it:

testWithReact("Can render", container => {
  act(() =>
    ReactDOMRe.render(
      <div> {"hello"->React.string} </div>,
      container,
    )
  )

  let div = container->DOM.findBySelectorAndTextContent("div", "hello")
  isTrue(div->Option.isSome)
})

Async assertion count plan

testAsync("My test", (cb) => (
  // your tests
  cb(~planned=2, ())
))

Env file

Add a retest.env.js to your project root directory for any setup.

rescript-test's People

Contributors

bloodyowl avatar remitbri avatar brettcannon avatar

Stargazers

Kevin Tonon avatar Ivan Tugay avatar Christian Rotzoll avatar MerlotRain avatar NAMEGORM avatar Alex Michael Berry avatar ᴍᴜǫɪᴜ ʜᴀɴ (韩暮秋) avatar  avatar Sora Morimoto avatar  avatar Kamweti Muriuki avatar Rob Bertram avatar SelasieHanson avatar Benjamin Schandera avatar Shaun Chong avatar Andrejs Agejevs avatar Gorka Cesium avatar Tino Thamjarat avatar Pedro Castro avatar Adam Harris avatar shellboy avatar  avatar Ilya Suzdalnitskiy avatar Leo avatar Anton Tuzhik avatar Ezio Lin avatar Mike Skoe avatar Takahiro Sato avatar YONGJAE LEE(이용재) avatar Alain Armand avatar Serhii Potapov avatar Sofiane Djellouli avatar Tamim Arafat avatar Sergey Zhukaev avatar luooooob avatar Christopher Tritton avatar Nick Mazuk avatar  avatar XLor avatar tkovs avatar Jason Smythe avatar Guillem avatar  avatar Antonín Simerský avatar Jihchi Lee avatar celso avatar Bernardo Gurgel avatar Christoph Knittel avatar Max Thirouin avatar Brad Pillow avatar Allain Lalonde avatar Rodrigo Oler avatar Diel Duarte avatar Seunguk Lee avatar Paul Tsnobiladzé avatar Marcin Dziewulski avatar Jasim A Basheer avatar Florian Hammerschmidt avatar quqiufeng avatar Fabien Bourgeois avatar WON SEOB SEO avatar Victor Nakoryakov avatar Artem Samofalov avatar Sergey Samokhov avatar Misha Bergal avatar Joe Badaczewski avatar Alexey Golev avatar Roman Hossain Shaon avatar Corentin Leruth avatar Vinicius Sales avatar Hyeseong Kim avatar Rolf Erik Lekang avatar savi2w avatar Nikita avatar Gabriel Rubens Abreu avatar Tom Ekander avatar Diogo Mafra avatar Tomasz Cichocinski avatar

Watchers

James Cloos avatar  avatar  avatar

rescript-test's Issues

Issues with windows 11

Hello I am working on Windows 11 (my personal laptop) with ReScript 11. I am looking to learn more about ReScript and want to explore testing. This framework looks to be all i need, but it doesn't seem to be working correctly

  1. it looks like the retest cli is being squashed by windows (a terminal window pops up and closes; i don't see anything in the event log
  2. I have been runnign directly node ./node_modules/rescript-test/bin/retest.mjs
  3. that only works if I path specifically to the test file, the wildcarding isn't working, e.g.,
  4. works: node ./node_modules/rescript-test/bin/retest.mjs tests/entities/parser/test_parser.bs.js
  5. doesn't work: node ./node_modules/rescript-test/bin/retest.mjs tests/entities/parser/*.bs.js
  6. doesn't work node ./node_modules/rescript-test/bin/retest.mjs tests/entities/**/test_parser.bs.js

I am a hobbiest at this point in my career (software executive) and have some rusty skills - so I may be missing something obviuos. I have added some debugging into retest.mjs and I don't think the glob nodeback is returning or isn't returning and the promises are not properly waited upon. The script does exit which indicates that the promises are not being waited on - but the code looks cool correct...

Logging in the event that I am missing something obvious. Will update if I uncover anything else

Add an assertion with a lazy operator

Sometimes the operator message can be quite heavy to compute. I suggest we add a new assertion function called for example assertionWithLazyOperator that takes a lazy operator.

bin

My Jenkins server at work breaks with newer versions of Retest:

09:21:54  file:///home/git/workspace/rets-node-lambda-rescript_master/node_modules/rescript-test/bin/retest.mjs:19
09:21:54  let { autoBoot, runTests } = await import(`../src/Test${suffix}`);
09:21:54                               ^^^^^
09:21:54  
09:21:54  SyntaxError: Unexpected reserved word
09:21:54      at Loader.moduleStrategy (internal/modules/esm/translators.js:122:18)
09:21:54      at async link (internal/modules/esm/module_job.js:42:21)

An older version, 0.6.5, works, I think because it uses CommonJS. Is there a way to support CommonJS? Yes, yes, I'm intimately aware of the struggle between MJS and CommonJS. However, in Node.js nothing is supported; case in point I'm in Node.js 14 which supports mjs 14 and "all kinds of weird things break". I'll revert to v0.6.5 for now, but if it sounds like a lot of work, I get it, I can help. As someone who's attempted twice to use mjs professionally and had all kinds of stupid stuff break, I empathize.

upgrade to Rescript version 10

Trying to install into a project using Rescript v10 using npm.

npm install rescript-test --save-dev
npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR! 
npm ERR! While resolving: [email protected]
npm ERR! Found: [email protected]
npm ERR! node_modules/rescript
npm ERR!   dev rescript@"^10.0.1" from the root project
npm ERR! 
npm ERR! Could not resolve dependency:
npm ERR! peer rescript@"^9.0.0" from [email protected]
npm ERR! node_modules/rescript-test
npm ERR!   dev rescript-test@"*" from the root project
npm ERR! 
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force, or --legacy-peer-deps
npm ERR! to accept an incorrect (and potentially broken) dependency resolution.

Installing `rescript-test` prior to changing `suffix` in `bsconfig.json`

First of all, thank you so much for taking the time to create this library 🙏.


rescript-test/bin/retest.mjs uses the inferred suffix when loading its own Test module:

yet the compiled output of that Test.res modle appears to depend on the suffix setting within the end-developers bsconfig.json file.

Therefore, if a developer installs rescript-test, finds out that it doesn't support the .bs.js suffixed files that actually contain ES6 import statements (which rescript currently outputs), and then attempts to fix that by changing suffix to .mjs within bsconfig.json, they will instead get this error:

Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/Users/dominic.chambers/dev/proj/node_modules/rescript-test/src/Test.mjs' imported from /Users/dominic.chambers/dev/proj/node_modules/rescript-test/bin/retest.mjs
    at new NodeError (internal/errors.js:322:7)
    at finalizeResolution (internal/modules/esm/resolve.js:308:11)
    at moduleResolve (internal/modules/esm/resolve.js:731:10)
    at Loader.defaultResolve [as _resolve] (internal/modules/esm/resolve.js:842:11)
    at Loader.resolve (internal/modules/esm/loader.js:89:40)
    at Loader.getModuleJob (internal/modules/esm/loader.js:242:28)
    at Loader.import (internal/modules/esm/loader.js:177:28)
    at importModuleDynamically (internal/modules/esm/translators.js:114:35)
    at exports.importModuleDynamicallyCallback (internal/process/esm_loader.js:30:14)
    at file:///Users/dominic.chambers/dev/proj/node_modules/rescript-test/bin/retest.mjs:42:41 {
  code: 'ERR_MODULE_NOT_FOUND'
}

Likely unbeknownst to the developer, this can actually be mitigated by deleting node_modules\rescript-test, and running yarn or npm install again, at which point it will re-build the Test module using the now appropriate settings within bsconfig.json.

Can i execute retest as npm script?

I created following sample unit test files.

[koji:hello_rescript]$ tree tests 
tests
├── MyTest.res
├── test_a
│   └── TestA.res
└── test_b
    ├── TestB.res
    └── test_b2
        └── TestB2.res

and my scripts on package.json

  "scripts": {
    "clean": "bsb -clean-world",
    "build": "bsb -make-world",
    "watch": "bsb -make-world -w",
    "test": "node_modules/rescript-test/bin/retest tests/**/*.bs.js"
  },

It will be executed tests on tests/*.bs.js only.
so, sub directories are ignored.

[koji:hello_rescript]$ npm test

> [email protected] test /home/koji/code/rescript/hello_rescript
> node_modules/rescript-test/bin/retest tests/**/*.bs.js

1/2: TestA
  PASS - a
  PASS - a2
2/2: TestB
  PASS - a
  PASS - a2

# Ran 2 tests (4 assertions)
# 2 passed
# 0 failed
[koji:hello_rescript]$ 

But, when i execute retest directlly, all tests in sub directories executed.(I expect this behavior)

[koji:hello_rescript]$ node_modules/rescript-test/bin/retest tests/**/*.bs.js
1/4: MyTest
  PASS - a
2/4: TestA
  PASS - a
  PASS - a2
3/4: TestB
  PASS - a
  PASS - a2
4/4: TestB2
  PASS - a
  PASS - a2

# Ran 4 tests (7 assertions)
# 4 passed
# 0 failed
[koji:hello_rescript]$ 

This behavior is not clear to me...
Is this because retest or npm ...?

Can't run retest

Hi, I'm trying to run the tests but getting this:

~/Development/own/dryer · (useCurrentUser±)
⟩ yarn test
yarn run v1.22.10
$ retest client/**/*.bs.js
node:internal/process/esm_loader:74
    internalBinding('errors').triggerUncaughtException(
                              ^

Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/Users/paul/Development/own/dryer/node_modules/rescript-test/src/Test.bs.js' imported from /Users/paul/Development/own/dryer/node_modules/rescript-test/bin/retest.mjs
    at new NodeError (node:internal/errors:329:5)
    at finalizeResolution (node:internal/modules/esm/resolve:323:11)
    at moduleResolve (node:internal/modules/esm/resolve:758:10)
    at Loader.defaultResolve [as _resolve] (node:internal/modules/esm/resolve:869:11)
    at Loader.resolve (node:internal/modules/esm/loader:86:40)
    at Loader.getModuleJob (node:internal/modules/esm/loader:230:28)
    at Loader.import (node:internal/modules/esm/loader:165:28)
    at importModuleDynamically (node:internal/modules/esm/translators:116:35)
    at exports.importModuleDynamicallyCallback (node:internal/process/esm_loader:30:14)
    at file:///Users/paul/Development/own/dryer/node_modules/rescript-test/bin/retest.mjs:19:57 {
  code: 'ERR_MODULE_NOT_FOUND'
}
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

My package.json:

{
  "name": "dryer",
  "private": true,
  "version": "0.1.0",
  "dependencies": {
    "@rails/actioncable": "^6.0.0",
    "@rails/activestorage": "^6.0.0",
    "@rails/ujs": "^6.0.0",
    "@rails/webpacker": "5.2.1",
    "@rescript/react": "^0.10.1",
    "@rescript/std": "^9.0.1",
    "bootstrap": "^4.6.0",
    "bs-webapi": "^0.19.1",
    "jquery": "^3.6.0",
    "node-sass-glob-importer": "^5.3.2",
    "popper.js": "^1.16.1",
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "rescript-future": "^1.1.0",
    "rescript-jzon": "^1.1.0",
    "rescript-request": "^1.1.0",
    "rescript-test": "^2.0.6"
  },
  "devDependencies": {
    "bs-platform": "^9.0.2",
    "webpack-dev-server": "^3.11.2"
  },
  "scripts": {
    "re:build": "bsb -make-world -clean-world",
    "re:watch": "bsb -make-world -clean-world -w",
    "test": "retest client/**/*.bs.js"
  }
}

My bsconfig.json:

{
  "$schema": "https://raw.githubusercontent.com/rescript-lang/rescript-compiler/master/docs/docson/build-schema.json",
  "name": "dryer",
  "bsc-flags": [
    "-bs-super-errors"
  ],
  "sources": [
    {
      "dir": "client/src",
      "subdirs": true
    }
  ],
  "package-specs": [
    {
      "module": "es6",
      "in-source": true
    }
  ],
  "reason": {
    "react-jsx": 3
  },
  "bs-dependencies": [
    "@rescript/react",
    "bs-webapi",
    "rescript-request",
    "rescript-future",
    "rescript-jzon",
    "rescript-test"
  ],
  "bs-dev-dependencies": [
  ],
  "external-stdlib" : "@rescript/std",
  "suffix": ".bs.js",
  "namespace": true,
  "ppx-flags": [],
  "refmt": 3
}

What am I doing wrong?

Fails to detect suffix if suffix is defined in package-specs

rescript-test tries to read the suffix at the top level of bsconfig.json like this:

{
  "suffix": ".mjs"
}

However, this is also a valid bsconfig.json:

{
  "package-specs": [
    {
      "in-source": false,
      "module": "es6",
      "suffix": ".mjs"
    },
    {
      "in-source": false,
      "module": "commonjs",
      "suffix": ".js"
    }
  ]
}

The suffix can be defined differently in each package-specs entry.

I wonder if the suffix should be an option explicitly passed to rescript-test?

Listed suffixes in `bin/retest.mjs` does not cover all suffixes suggested at rescript-lang.org

For example, when I ran npm create rescript-app on my project, the suffix chosen was .res.mjs. https://rescript-lang.org/docs/manual/latest/installation#new-project also lists both .res.js and .res.mjs as suffixes.

The line that hard-codes the suffixes seems to be:
https://rescript-lang.org/docs/manual/latest/installation#new-project

When I manually add the above suffixes, rescript-test works in my project.

Can you remove the compiler from test dependencies?

Hello. Thank you for this nice rescript implementation of tests.

Would you mind removing the dependency on the compiler? It is making our compilation to fail:

https://github.com/bloodyowl/rescript-test/blob/be462e6f6f553407eee56ae9d1ab160af26ff536/package.json#LL23-L26C5

We get the following error when compiling fresh (CI):

Dependency on rescript-test
Different compiler version: clean current repo
File "bsconfig.json", line 1
Error: package rescript-js not found or built 

Not sure if the problem comes from rescript-js or from just rescript compiler. But the thing is that it fails because it cleans the repo.

Or do you have experience addressing this kind of issues? If so, I will be happy to know how.

Wildcard test does not work (on Windows?)

On Windows, and my intuition says that's relevant.

In any case, using the wildcard syntax from your installation demo does not work, but specifying individual files works fine.

PS C:\blah\web> yarn test
yarn run v1.22.17
$ retest tests/*.mjs
internal/process/esm_loader.js:74
    internalBinding('errors').triggerUncaughtException(
                              ^

Error [ERR_MODULE_NOT_FOUND]: Cannot find module 'C:\blah\web\tests\*.mjs' imported from C:\blah\web\node_modules\rescript-test\bin\retest.mjs
    at finalizeResolution (internal/modules/esm/resolve.js:285:11)
    at moduleResolve (internal/modules/esm/resolve.js:708:10)
    at Loader.defaultResolve [as _resolve] (internal/modules/esm/resolve.js:819:11)
    at Loader.resolve (internal/modules/esm/loader.js:89:40)
    at Loader.getModuleJob (internal/modules/esm/loader.js:242:28)
    at Loader.import (internal/modules/esm/loader.js:177:28)
    at importModuleDynamically (internal/modules/esm/translators.js:114:35)
    at exports.importModuleDynamicallyCallback (internal/process/esm_loader.js:30:14)
    at file:///C:/Users/huntw/dev/swtor-companion/web/node_modules/rescript-test/bin/retest.mjs:67:41
    at Array.map (<anonymous>) {
  code: 'ERR_MODULE_NOT_FOUND'
}
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
PS C:\blah\web> yarn retest tests/MyTest.mjs
yarn run v1.22.17
$ C:\blah\web\node_modules\.bin\retest tests/MyTest.mjs
1/1: test test
  PASS - 1 should equal 1

# Ran 1 tests (1 assertions)
# 1 passed
# 0 failed
Done in 0.57s.
PS C:\blah\web> 

Trouble using with inline_test_ppx

I'm trying to use rescript-test with inline_test_ppx and am running into some difficulty. inline_test_ppx outputs files as lib/bs/__inline_test.*.mjs. This seems to cause two problems, first it trips up the path logic in rescript-test resulting in

npx retest lib/bs/__inline_test.*.mjs
Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/Users/myuser/dev/myproject/rescript/node_modules/rescript-test/lib/bs/src/Test.mjs' imported from /Users/myuser/dev/myproject/rescript/node_modules/rescript-test/bin/retest.mjs

This can be worked around by changing the path provided to retest

npx retest ../rescript/lib/bs/__inline_test.*.mjs
//it runs 

Unfortunately there is another issue, rescript-test always reports 0 tests even though it's picking up the correct files. This appears to be due to inline_test_ppx using an async require of the target file. For example, the lib/bs/__inline_test.mymodule.mjs will contain something like

import("../../src/mymodule.mjs").catch((e) => {
    if (e.code !== "ERR_MODULE_NOT_FOUND") reject(e)
})

This causes rescript-test to always find 0 tests to run. If I manually change it to a synchronous import like so

import "../../src/mymodule.mjs"

then the tests are found and everything works correctly. I'm not quite sure why rescript-test isn't working with that async import style.

Unable to figure out configuration when "in-source" is false

Hi!
I use in-source:false in my BS configuration to compile the JavaScript files in a different folder outside of my ReScript project. I tried different solutions to get the test file to be compiled outside of the main directory but I couldn't make it work. The error message I get may suggest that there is no bin folder because my JS files get compiled in a lib folder.
Here is the repo for the project I am trying to add tests to: https://github.com/claudebarde/rescript-michelson
Thank you for your help!

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.