{"id":13680538,"url":"https://github.com/dusty-phillips/rescript-zora","last_synced_at":"2025-04-10T12:54:13.837Z","repository":{"id":37450348,"uuid":"359228835","full_name":"dusty-phillips/rescript-zora","owner":"dusty-phillips","description":"Lightning-fast testing for a lightning-fast compiler","archived":false,"fork":false,"pushed_at":"2024-05-21T14:30:47.000Z","size":175,"stargazers_count":51,"open_issues_count":0,"forks_count":11,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-05-21T15:45:33.718Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dusty-phillips.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"patreon":"dustyphillipscodes","github":"dusty-phillips"}},"created_at":"2021-04-18T18:58:07.000Z","updated_at":"2024-06-19T01:40:45.676Z","dependencies_parsed_at":"2024-05-06T22:31:11.339Z","dependency_job_id":"71a3b2d8-7b2e-465c-a893-40c84b38cd20","html_url":"https://github.com/dusty-phillips/rescript-zora","commit_stats":{"total_commits":65,"total_committers":2,"mean_commits":32.5,"dds":0.01538461538461533,"last_synced_commit":"76e08155f24d8aa8c8bbdf7553522bbc5192039f"},"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dusty-phillips%2Frescript-zora","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dusty-phillips%2Frescript-zora/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dusty-phillips%2Frescript-zora/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dusty-phillips%2Frescript-zora/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dusty-phillips","download_url":"https://codeload.github.com/dusty-phillips/rescript-zora/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248221294,"owners_count":21067508,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-02T13:01:18.235Z","updated_at":"2025-04-10T12:54:13.818Z","avatar_url":"https://github.com/dusty-phillips.png","language":"JavaScript","funding_links":["https://patreon.com/dustyphillipscodes","https://github.com/sponsors/dusty-phillips"],"categories":["ReScript","JavaScript"],"sub_categories":[],"readme":"# rescript-zora: Lightning-fast unit tests\n\nThis package provides [ReScript](https://rescript-lang.org/) bindings for the\n[Zora](https://github.com/lorenzofox3/zora) testing framework. ReScript and Zora\ngo very well together because they have a common mission of SPEED.\n\nIn the interest of maintaining that speed, this package is asynchronous by\ndefault, though you can create blocking tests if you prefer.\n\nThis package mostly just binds directly to Zora, but there are a couple\nniceties to help work with ReScript promises and the standard library.\n\n## If you've used older versions of this package\n\n### 4 → 5\n\nThe code was updated to ReScript 11.\n\nNearly all check functions have gained an optional `~msg` argument for passing\nin the message for the check. This makes the message optional, defaulting to\nwhat Zora provides as a message.\n\nThe `resultError` function now accepts a check function to verify the value\ncontained by the `Error`.\n\nThere is a new `ignoreValue` check function to pass to the `option*` and\n`result*` functions when the values are inconsequential and the type of variant\nis the purpose of the test.\n\n### 3 → 4\n\nI've migrated everything to async/await syntax and it now requires\nReScript 10.1. You'll need to convert any non-blocking tests in your\nexisting codebase to return promise or define them with async, but\nyou don't need to throw `done()` calls in all your async tests.\n\n## Installation\n\n_Note: If you don't have a ReScript 9.1.1 project initialized already, the\nfastest way to get one is with `npx rescript init myproject`._\n\nInstall [zora](https://github.com/lorenzofox3/zora) and this package:\n\n```\nnpm install --save-dev @dusty-phillips/rescript-zora\n```\n\nAdd `@dusty-phillips/rescript-zora` as a dependency in your `rescript.json`:\n\n```\n\"bs-dev-dependencies\": [\"@dusty-phillips/rescript-zora\"]\n```\n\n## Suggested configuration\n\nRecent versions of node seem to cooperate better if you explicitly use the .mjs or\n.cjs suffix for your files. So you'll want your `rescript.json` to contain either:\n\n- suffix: `.mjs` and module: `esmodule`\n- suffix: `.cjs` and module: `commonjs`\n\nI use `.mjs` in this configuration, but I have tested it with `.cjs` and it seems\nto work.\n\nYou'll probably also want to add the following `package-specs` configuration to\nyour `rescript.json`:\n\n```json\n  \"suffix\": \".mjs\",\n  \"package-specs\": {\n    \"module\": \"esmodule\",\n    \"in-source\": true\n  },\n```\n\nIf you like to keep your tests separate from your source code, you'll need to\nadd that directory so ReScript will compile your test files:\n\n```json\n  \"sources\": [\n    {\n      \"dir\": \"src\",\n      \"subdirs\": true\n    },\n    { \"dir\": \"tests\", \"subdirs\": true, \"type\": \"dev\" }\n  ],\n```\n\nSo a minimal `rescript.json` might look like this:\n\n```json\n{\n  \"name\": \"myproject\",\n  \"version\": \"2.0.0\",\n  \"suffix\": \".mjs\",\n  \"sources\": [\n    {\n      \"dir\": \"src\",\n      \"subdirs\": true\n    },\n    { \"dir\": \"tests\", \"subdirs\": true, \"type\": \"dev\" }\n  ],\n  \"package-specs\": {\n    \"module\": \"esmodule\",\n    \"in-source\": true\n  },\n  \"bs-dev-dependencies\": [\"@dusty-phillips/rescript-zora\"]\n}\n```\n\n## Stand-alone test\n\nThe simplest possible Zora test looks like this:\n\n```rescript\n// tests/simple.test.res\nopen Zora\n\nzoraBlock(\"should run a test synchronously\", t =\u003e {\n  let answer = 3.14\n  t-\u003eequal(answer, 3.14, ~msg=\"Should be a tasty dessert\")\n})\n```\n\nBuilding this with ReScript will output a `tests/simple.mjs` file that\nyou can run directly with `node`:\n\n```tap\n╰─○ node tests/standalone.js\nTAP version 13\n# should run a test asynchronously\nok 1 - Should answer the question\n# should run a test synchronously\nok 2 - Should be a tasty dessert\n1..2\n\n# ok\n# success: 2\n# skipped: 0\n# failure: 0\n```\n\nThis output is in [Test Anything Protocol](https://testanything.org/) format.\nThe [zora docs](https://github.com/lorenzofox3/zora) go into more detail on how\nit works with Zora.\n\n## Combining tests\n\nYou can include multiple `zoraBlock` statements, or you can pass the `t` value\ninto the `block` function:\n\n```rescript\nopen Zora\n\nzoraBlock(\"Should run some simple blocking tests\", t =\u003e {\n  t-\u003eblock(\"should greet\", t =\u003e {\n    t-\u003eok(true, ~msg=\"hello world\")\n  })\n\n  t-\u003eblock(\"should answer question\", t =\u003e {\n    let answer = 42\n    t-\u003eequal(answer, 42, ~msg=\"should be 42\")\n  })\n})\n```\n\n## Running tests in parallel (async)\n\nThe `Block` in `zoraBlock` indicates that this is a blocking test. It's faster\nto run multiple independent tests in parallel:\n\n```rescript\n// tests/standaloneParallel.res\n\nopen Zora\n\nzora(\"should run a test asynchronously\", async t =\u003e {\n  let answer = 42\n  t-\u003eequal(answer, 42, ~msg=\"Should answer the question\")\n})\n\nzora(\"should run a second test at the same time\", async t =\u003e {\n  let answer = 3.14\n  t-\u003eequal(answer, 3.14, ~msg=\"Should be a tasty dessert\")\n})\n```\n\nNote the absence of `zoraBlock`, and the presence of `async`. You can\nawait other promises inside the test if you want.\n\n## Combining parallel tests\n\nYou can nest parallel async tests inside a blocking or non-blocking test, and\nrun blocking tests alongside parallel tests:\n\n```rescript\n// parallel.test.res\nopen Zora\n\nlet wait = (amount: int) =\u003e {\n  Js.Promise2.make((~resolve, ~reject) =\u003e {\n    reject-\u003eignore\n    Js.Global.setTimeout(_ =\u003e {\n      resolve(. Js.undefined)\n    }, amount)-\u003eignore\n  })\n}\n\nzora(\"Some Parallel Tests\", async t =\u003e {\n  let state = ref(0)\n\n  t-\u003etest(\"parallel 1\", async t =\u003e {\n    {await wait(10)}-\u003e ignore\n    t-\u003eequal(state.contents, 1, ~msg=\"parallel 2 should have incremented by now\")\n    state.contents = state.contents + 1\n    t-\u003eequal(state.contents, 2, ~msg=\"parallel 1 should increment\")\n  })\n\n  t-\u003etest(\"parallel 2\", async t =\u003e {\n    t-\u003eequal(state.contents, 0, ~msg=\"parallel 2 should be the first to increment\")\n    state.contents = state.contents + 1\n    t-\u003eequal(state.contents, 1, ~msg=\"parallel 2 should increment\")\n  })\n\n  t-\u003etest(\"parallel 3\", async t =\u003e {\n    {await wait(20)}-\u003eignore\n    t-\u003eequal(state.contents, 2, ~msg=\"parallel 1 and 2 should have incremented by now\")\n    state.contents = state.contents + 1\n    t-\u003eequal(state.contents, 3, ~msg=\"parallel 3 should increment last\")\n  })\n})\n```\n\nThis is the default and preferred test setup (zora and test) to take advantage of\nparallelism for speed. Note that you can combine parallel and blocking tests\nin the same `zora` or `zoraBlocking` block as well.\n\n## Test runner\n\nYou probably don't want to run each of your test files using separate `node`\ncommands, though. You can use any TAP compliant test runner ([see\nhere](https://github.com/sindresorhus/awesome-tap) for a list), but your best\nbet is probably to use Zora's bundled\n[pta](https://github.com/lorenzofox3/zora/tree/master/pta) runner with\n[onchange](https://github.com/Qard/onchange) for watching for file changes:\n\n```plaintext\nnpm install --save-dev pta onchange\n```\n\nWith these installed, you can set the `test` command in your `scripts` as follows:\n\n```json\n  \"test\": \"onchange --initial '{tests,src}/*.js' -- pta 'tests/*.test.js'\",\n```\n\nOr, if you prefer to keep your tests alongside your code in your `src` folder:\n\n```json\n  \"test\": \"onchange --initial 'src/*.js' -- pta 'src/*.test.js'\",\n```\n\nNow `npm test` will do what you expect: run a test runner and watch for file\nchanges.\n\n## Skip, only, and fail\n\nZora exposes functions to skip tests if you need to. If you have a failing\ntest, just replace the call to `Zora.test` with a call to `Zora.skip`. Or, if\nyou're running blocking tests, replace `Zora.block` with `Zora.blockSkip`.\n\nFor example:\n\n```rescript\nopen Zora\n\nzora(\"should skip some tests\", t =\u003e {\n  t-\u003eskip(\"broken test\", t =\u003e {\n    t-\u003efail(~msg=\"Test is broken\")\n  })\n\n  t-\u003eblockSkip(\"also broken\", t =\u003e {\n    t-\u003efail(~msg=\"Test is broken, too\")\n  })\n\n})\n```\n\nThe above also illustrates the use of the `Zora.fail` assertion to force a test\nto be always failing.\n\nIf you want to run and debug a single test, you can run it in `only` mode. As\nwith skip, change the test's name from `test` to `only` or `block` to\n`blockOnly`. You must also change the top level `zora`/`zoraBlock` to\n`zoraOnly`/`zoraBlockOnly`.\n\n```rescript\nopen Zora\n\nzoraOnly(\"should skip some tests\", t =\u003e {\n  t-\u003eonly(\"only run this test\", t =\u003e {\n    t-\u003eok(true, ~msg=\"Only working test\")\n  })\n\n  t-\u003etest(\"don't run this test\", t =\u003e {\n    t-\u003efail(~msg=\"Test is broken\")\n  })\n\n})\n```\n\nHowever, `only` tests are intended only in development mode and zora will fail\nby default if you try to run one. To run in only mode, you can run:\n\n```shell\nnpm test -- --only\n```\n\nor\n\n```shell\nZORA_ONLY=true npm test\n```\n\nIf you use this feature a lot, you could also consider putting additional test\ncommands in your `package.json` scripts, one for local only development and one\nfor CI:\n\n```json\n\"test\": \"onchange --initial '{tests,src}/*.js' -- pta 'tests/*.test.js'\",\n\"test:only\": \"onchange --initial '{tests,src}/*.js' -- pta --only 'tests/*.test.js'\",\n\"test:ci\": \"pta 'tests/*.test.js'\",\n```\n\n## Assertions\n\nThis library models all the default assertions provided by Zora except for\nthose dealing with raising exceptions, which don't map neatly to ReScript\nexceptions. There are additional bindings for checking if a ReScript `option`\nis `Some()` or `None` or if a `Result` is `Ok()` or `Error()` and asserting\non the value therein (except for `None` as there is no value to check). A\n`ignoreValue` function is provided in those instances where asserting on the\nvalue is unimportant.\n\nIn the interest of avoiding bloat, I do not intend to add a lot of other\nReScript-specific assertions.\n\n```rescript\n//tests/assertions.test.res\nopen Zora\n\nzora(\"Test assertions\", t =\u003e {\n  t-\u003eequal(42, 42, ~msg=\"Numbers are equal\")\n  t-\u003enotEqual(42, 43, ~msg=\"Numbers are not equal\")\n  let x = {\"hello\": \"world\"}\n  let y = x\n  let z = {\"hello\": \"world\"}\n  t-\u003eis(x, x, ~msg=\"object is object\")\n  t-\u003eis(x, y, ~msg=\"object is object\")\n  t-\u003eisNot(x, z, ~msg=\"object is not object with same values\")\n  t-\u003eequal(x, z, ~msg=\"Object is deep equal\")\n  t-\u003eok(true, ~msg=\"boolean is ok\")\n  t-\u003enotOk(false, ~msg=\"boolean is not ok\")\n  t-\u003eoptionNone(None, ~msg=\"None is None\")\n  t-\u003eoptionSome(Some(x), (t, n) =\u003e t-\u003eequal(n[\"hello\"], \"world\", ~msg=\"option should be hello world\"))\n  t-\u003eresultError(Error(x), (t, n) =\u003e t-\u003eequal(n[\"hello\"], \"world\", ~msg=\"Is Error Result\"))\n  t-\u003eresultOk(Ok(x), (t, n) =\u003e t-\u003eequal(n[\"hello\"], \"world\", ~msg=\"Is Ok Result\"))\n})\n```\n\n## Running in the browser\n\nZora supports running tests in the browser, but I have not tested it with this\nReScript implementation. I am open to PRs that will make this ReScript\nimplementation work in the browser if changes are required.\n\n## Source Maps\n\nThe biggest problem with this library is that test failures point to the lines\nin the compiled js files instead of ReScript itself. If someone knows how to\nconfigure ReScript and zora to use source maps, I'd love a PR.\n\n## Contributing\n\nPRs are welcome.\n\n## Releasing\n\nThis is for my reference\n\n- update the version in `rescript.json`\n- `npx np`\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdusty-phillips%2Frescript-zora","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdusty-phillips%2Frescript-zora","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdusty-phillips%2Frescript-zora/lists"}