ReScriptでJestを使う

# ReScriptのインストール[^1]
[^1]:https://rescript-lang.org/docs/manual/latest/installation#new-project
```SH:SH
npm create rescript-app@latest
```
<details><summary>インストールの詳細</summary>

```SH:SH
┌  create-rescript-app 1.7.1
│
◇  Welcome to ReScript! ─────────────────────────────────╮
│                                                        │
│  Fast, Simple, Fully Typed JavaScript from the Future  │
│  https://rescript-lang.org                             │
│                                                        │
├────────────────────────────────────────────────────────╯
│
◇  New Project ───────────────────────────────────────────╮
│                                                         │
│  Create a new ReScript 11 project with modern defaults  │
│  ("Core" standard library, JSX v4)                      │
│                                                         │
├─────────────────────────────────────────────────────────╯
│
◆  What is the name of your new ReScript project?
│  jest-test_
│
◆  Select a template
│  ○ Vite
│  ○ Next.js
│  ● Basic (Command line hello world app)
│
◆  ReScript version?
│  ● 11.1.1
│  ○ 11.1.0
│  ○ 11.0.1
│  ○ 11.0.0
│
◆  ReScript Core version?
│  ● 1.5.0
│  ○ 1.4.0
│  ○ 1.3.0
│  ○ 1.2.0
│  ○ 1.1.0
│  ○ 1.0.0
│
◇  Project created.
│
└  Happy hacking!
```
</details>

# rescript-jestのインストール[^2][^3]
[^2]:https://github.com/glennsl/rescript-jest
[^3]:ReScriptのインストールで作成されたディレクトリ（今回の場合は`jest-test`）で実行します。
```SH:SH
npm install --save-dev @glennsl/rescript-jest
```
# `rescript.json`の編集
```JSON:rescript.json
{
  ...
  "bs-dev-dependencies": ["@glennsl/rescript-jest"]
}
```
`"sources"`で`"type": "dev"`が指定されたディレクトリに置かれたファイルがコンパイルされるときに`@glennsl/rescript-jest`を探してくれます。
***
```JSON:rescript.json
"sources": [
  {
    "dir": "src"
    "subdirs": true
  },
  {
    "dir": "__tests__",
    "type": "dev"
  }
]
```
`src`と同じ階層にある`__tests__`にUnit Test用のファイルを置くことにします。
***
```JSON:rescript.json
  "package-specs": {
    "module": "commonjs",
    "in-source": true
  },
```
`commonjs`形式のモジュールにします。[^4]
[^4]:デフォルトでは`esmodule`になってました。
# `package.json`の編集
```JSON:package.json
  "scripts": {
  ...
  "test": "jest"
}
```
`npm run test`で`Jest`が実行されるようにします。
# ディレクトリ`__tests__`の作成[^3]
```SH:SH
mkdir __tests__
```
# 設定まとめ[^5]
[^5]:`rescript.json`は`ReScript`の設定ファイルで、`package.json`は`npm`の設定ファイルだということを、ようやく理解しました。
<details><summary>rescript.json</summary>

```JSON:rescript.json
{
  "name": "jest-test",
  "sources": [
    {
      "dir": "src",
      "subdirs": true
    },
    {
      "dir": "__tests__",
      "type": "dev"
    }
  ],
  "package-specs": {
    "module": "commonjs",
    "in-source": true
  },
  "suffix": ".res.js",
  "bs-dependencies": [
    "@rescript/core"
  ],
  "bs-dev-dependencies": [
    "@glennsl/rescript-jest"
  ],
  "bsc-flags": [
    "-open RescriptCore"
  ]
}
```
</details>
<details><summary>package.json</summary>

```JSON:package.json
{
  "name": "jest-test",
  "version": "0.0.0",
  "scripts": {
    "res:build": "rescript",
    "res:clean": "rescript clean",
    "res:dev": "rescript -w",
    "test": "jest"
  },
  "keywords": [
    "rescript"
  ],
  "author": "",
  "license": "MIT",
  "dependencies": {
    "@rescript/core": "^1.5.0",
    "rescript": "^11.1.1"
  },
  "devDependencies": {
    "@glennsl/rescript-jest": "^0.11.0"
  }
}
```
</details>

# Unit Testにかけるプログラム
```ReScript:Ex09.res
// 目的：整数のリストの長さを返す
// length : int list -> int
let rec length = (lst) => switch lst {
| list{} => 0 
| list{_, ...rest} => 1 + length(rest) 
}

// 目的：受け取ったリストの中から偶数のみを抜き出したリストを返す
// even : int list -> int list
let rec even = (lst) => switch lst {
| list{} => list{} 
| list{first, ...rest} => 
    if mod(first, 2) == 0 {
      list{first, ...even(rest)}
    } else {
      even(rest)
    }
}

// 目的：リスト中の文字列をつなげた文字列を返す
// concat : string list -> string
let rec concat = (lst) => switch lst {
| list{} => "" 
| list{first, ...rest} => first ++ concat(rest)
}
```
# Unit Test
```ReScript:Ex09_test.res
open Jest
open Ex09

describe("length", () => {
  open Expect

  test("containing multiple items", () =>
    expect(length(list{2, 1, 6, 4, 7})) -> toBe(5))
})

describe("even", () => {
  open Expect

  test("containing multiple numbers", () =>
    expect(even(list{1, 2, 6, 4, 7})) -> toEqual(list{2, 6, 4}))
})

describe("concat", () => {
  open Expect

  test("containing multiple items", () =>
    expect(concat(list{"春", "夏", "秋", "冬"})) -> toBe("春夏秋冬"))
})
```
`int`と`String`の一致は`toBe`でした。`list`の一致は`toEqual`を使うようです。

# ディレクトリ構成
```
jest-test/
├── rescript.json
├── package.json
├── src/
│   └── Ex09.res
└── __tests__/
    └── Ex09_test.res
```
# ビルドとテストの実行
```SH:ビルドとテスト
npm run res:build
npm run test
```
```SH:テスト結果
> jest-test@0.0.0 test
> jest

 PASS  __tests__/Ex09_test.res.js
  length
    ✓ containing multiple items (1 ms)
  even
    ✓ containing multiple numbers
  concat
    ✓ containing multiple items

Test Suites: 1 passed, 1 total
Tests:       3 passed, 3 total
Snapshots:   0 total
Time:        0.108 s, estimated 1 s
Ran all test suites.