10
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【脱create-react-app】pnpm + vite + React + vitest を動かす!

Posted at

create-react-app is dead

以下の記事が凄くわかりやすいです。

一部引用

Releasesを見ていくと、最後のリリースは去年の4月です。近年のリリース日をまとめるとこんな感じです。

キャプチャ.PNG

viteに移行しましょう。ついでにpnpmにも入門してみます。

今回は、以下をやってみます!

① pnpmインストール
② vite + react 環境作成
③ vitest インストール
④ vitest + React Testing Library 環境作成

0⃣ ver確認

node -v # v20.9.0
pnpm -v # 9.11.0

① pnpmのインストール

公式ドキュメントを見つつ、お好みの方法でインストールします
nodeはデフォルトでnpmもおまけにインストールしてくれているはずなので、これがシンプルで楽なはず

npm install -g pnpm

そもそもpnpmって?

npmのお兄ちゃん

特に

  • npmに比べ動作が速い
  • node_modulesをプロジェクト間で共有する

の2点が趣味開発してるマシン的には嬉しいと思いました

② vite + react環境の作成

ドキュメントに従い、 create vite コマンドでプロジェクトを作成します

create viteコマンドでプロジェクトを作成する

pnpm create vite my-react-ts-app --template react-ts

一瞬で終わる!
昔create-react-appしたときより早い気がする。きのせい?

c/work/react$ pnpm create vite my-react-ts-app --template react-ts

Scaffolding project in c/work/react/my-react-ts-app...

Done. Now run:

  cd my-react-ts-app
  pnpm install
  pnpm run dev

コマンドラインに従い、パッケージのインストールとreact devサーバーの起動を行ってみます

  cd my-react-ts-app
  pnpm install
  pnpm run dev

pnpmコマンドでパッケージをインストール

pnpm install

実行します。

c/work/react/my-react-ts-app$   pnpm install       

   ╭──────────────────────────────────────────────────────────────────╮
   │                                                                  │
   │                Update available! 9.11.0 → 9.12.0.                │
   │   Changelog: https://github.com/pnpm/pnpm/releases/tag/v9.12.0   │
   │                Run "pnpm add -g pnpm" to update.                 │
   │                                                                  │
   │         Follow @pnpmjs for updates: https://x.com/pnpmjs         │
   │                                                                  │
   ╰──────────────────────────────────────────────────────────────────╯

Packages: +192
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++  
Progress: resolved 229, reused 140, downloaded 52, added 192, done


dependencies:     
+ react 18.3.1    
+ react-dom 18.3.1

devDependencies:
+ @eslint/js 9.12.0
+ @types/react 18.3.11
+ @types/react-dom 18.3.0
+ @vitejs/plugin-react 4.3.2
+ eslint 9.12.0
+ eslint-plugin-react-hooks 5.1.0-rc-fb9a90fa48-20240614
+ eslint-plugin-react-refresh 0.4.12
+ globals 15.10.0
+ typescript 5.6.2
+ typescript-eslint 8.8.0
+ vite 5.4.8

Done in 1m 31.6s

Done in 1m 31.6s

早い!気がします

react devサーバーを実行

pnpm run dev

実行します

c/work/react/my-react-ts-app$   pnpm run dev

> my-react-ts-app@0.0.0 dev c/work/react/my-react-ts-app
> vite


  VITE v5.4.8  ready in 4632 ms

  ➜  Local:   http://localhost:5173/
  ➜  Network: use --host to expose
  ➜  press h + enter to show help

VITE v5.4.8 ready in 4632 ms

早い!気がします

キャプチャ.PNG

http://localhost:5173/ で問題なく表示されていることを確認します

とにかく早いですねー

③ vitest インストール

テストライブラリもインストールしていきます。

vitestのインストール

ドキュメントに従ってインストールしていきます。

pnpm add -D vitest

実行します

c/work/react/my-react-ts-app$ pnpm add -D vitest
Packages: +29
+++++++++++++++++++++++++++++
Progress: resolved 258, reused 212, downloaded 9, added 29, done

devDependencies:
+ vitest 2.1.2

Done in 28.3s

インストールされました

vitestを実行してみる

testファイルを作成していきます

mkdir __test__
touch __test__/sample.test.ts 

テストを書いてみます

__test__/sample.test.ts
import { describe, expect, it } from "vitest";

describe("sample", () => {
    it("1 eq 1", () => {
        expect(1).toBe(1)
    })
})

テストが実行できるよう、package.jsonを編集します

    "dev": "vite",
+   "test":"vitest",
    "build": "tsc -b && vite build",

testスクリプトを追記します

package.json
{
  "name": "my-react-ts-app",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "test":"vitest",
    "build": "tsc -b && vite build",
    "lint": "eslint .",
    "preview": "vite preview"
  },
  "dependencies": {
    "react": "^18.3.1",
    "react-dom": "^18.3.1"
  },
  "devDependencies": {
    "@eslint/js": "^9.11.1",
    "@types/react": "^18.3.10",
    "@types/react-dom": "^18.3.0",
    "@vitejs/plugin-react": "^4.3.2",
    "eslint": "^9.11.1",
    "eslint-plugin-react-hooks": "^5.1.0-rc.0",
    "eslint-plugin-react-refresh": "^0.4.12",
    "globals": "^15.9.0",
    "typescript": "^5.5.3",
    "typescript-eslint": "^8.7.0",
    "vite": "^5.4.8",
    "vitest": "^2.1.2"
  }
}

では、テストを実行して1は1なのか確かめます

pnpm run test

コマンドを実行します

c/work/react/my-react-ts-app$ pnpm run test

> my-react-ts-app@0.0.0 test c/work/react/my-react-ts-app
> vitest


 DEV  v2.1.2 c/work/react/my-react-ts-app

 ✓ __test__/sample.test.ts (1)
   ✓ sample (1)
     ✓ 1 eq 1

 Test Files  1 passed (1)
      Tests  1 passed (1)
   Start at  09:39:24
   Duration  9.43s (transform 268ms, setup 0ms, collect 789ms, tests 7ms, environment 1ms, 
prepare 6.44s)


 PASS  Waiting for file changes...
       press h to show help, press q to quit

✓ 1 eq 1

良い感じですね

そもそもvitestって?

jestライクなテスティングライブラリです

特に

  • viteと統合されている(から?HMRがはやい)
  • ESM, CJSを意識しなくていい(はず)
  • jestライク

の3点が個人的嬉しいところです

④ vitest + React Testing Library 環境作成

実行環境を提供するライブラリのインストール

node環境上には、デフォルトではDOMを再現する機能が存在しません
DOMを再現するためのライブラリをインストールします

pnpm add -D jsdom

コマンドを実行します

c/work/react/my-react-ts-app$ pnpm add -D jsdom
Packages: +36
++++++++++++++++++++++++++++++++++++
Progress: resolved 293, reused 227, downloaded 29, added 36, done

devDependencies:
+ jsdom 25.0.1  

Done in 53.5s

インストール後、vite.config.ts を編集します

+ // Vitestの型を追加する
+ /// <reference types="vitest" />

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [react()],
+ test: {
+   // デフォルトのnode環境ではDOMを再現できないので、jsdom環境を使用する
+   environment: "jsdom",
+ },
})


準備完了です!!!

vite.config.ts
// Vitestの型を追加する
/// <reference types="vitest" />

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [react()],
  test: {
    // デフォルトのnode環境ではDOMを再現できない
    environment: "jsdom",
  },
})

Reactコンポーネントをテストするためのライブラリをインストールする

Reactはjsx、tsxという特殊な形式のjs、tsを利用します
デフォルトのvitest、jsdomだけではこのReactコンポーネントをレンダリングしたり、操作できません

そこで、Reactコンポーネントをレンダリング・操作するためのライブラリを別途追加します

pnpm add -D @testing-library/react @testing-library/jest-dom @testing-library/user-event

コマンドを実行します

c/work/react/my-react-ts-app$ pnpm add -D @testing-library/react 
@testing-library/jest-dom @testing-library/user-event
Packages: +25
+++++++++++++++++++++++++
Progress: resolved 318, reused 257, downloaded 24, added 25, done

devDependencies:
+ @testing-library/jest-dom 6.5.0
+ @testing-library/react 16.0.1
+ @testing-library/user-event 14.5.2

Done in 1m 2.9s

テストを書いてみます

touch __test__/App.test.tsx

こんな感じのテストケースを用意しました。

__test__/App.test.tsx
import { beforeEach, describe, expect, it } from "vitest";
import { cleanup, render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import '@testing-library/jest-dom/vitest';

import React from "react";
import App from "../src/App"

// デフォルトではクリーンアップされないため、Eachで実行する
beforeEach(() => {
    cleanup();
});
// userインスタンスのセットアップ
const user = userEvent.setup();

describe("tsx sample", () => {
    it("viteとReactの画像が表示されていることを確認する", () => {
        // コンポーネントをレンダリングする
        render(<App />)

        // レンダリングされたDOM上から要素を取得する
        const imgElementArray = screen.getAllByRole("img")

        // アサートする
        // 本来はテストケースごとに1アサーションが良いってt-wadaさんが言ってた
        expect(imgElementArray.length).toBe(2)
        expect(imgElementArray[0].getAttribute("alt")).toBe("Vite logo")
        expect(imgElementArray[1].getAttribute("alt")).toBe("React logo")
    })
    it("use jest-dom sample", () => {
        // コンポーネントをレンダリングする
        render(<App />)

        // 拡張されたマッチャーを使用できる
        expect(screen.getByText("count is 0")).toBeInTheDocument()
    })
    it("use user-event sample", async () /* async関数をテストケース内で使用する */ => {
        // コンポーネントをレンダリングする
        render(<App />)
        // レンダリングされたDOM上から要素を取得する
        const countButtonElement = screen.getByRole("button")

        // userの操作を再現する
        // clickはasync関数なので、awaitする
        await user.click(countButtonElement)

        // 拡張されたマッチャーを使用できる
        expect(screen.getByText("count is 1")).toBeInTheDocument()
    })
})

先ほどaddした以下のライブラリが何をしてくれているか確認します

@testing-library/react
@testing-library/jest-dom
@testing-library/user-event

@testing-library/react

__test__/App.test.tsx
import { cleanup, render, screen } from "@testing-library/react";

@testing-library/react は、上述したように、
render 関数やscreen 関数で、Reactコンポーネントをレンダリングしてくれています。

__test__/App.test.tsx
        // コンポーネントをレンダリングする
        render(<App />)

        // レンダリングされたDOM上から要素を取得する
        const imgElementArray = screen.getAllByRole("img")

こんなかんじですね

@testing-library/jest-dom

__test__/App.test.tsx
import '@testing-library/jest-dom/vitest';

jest-domはvitestのマッチャー(比較するメソッド)を拡張してくれています

キャプチャ.PNG

__test__/App.test.tsx
        // 拡張されたマッチャーを使用できる
        expect(screen.getByText("count is 0")).toBeInTheDocument()

今回は toBeInTheDocument() マッチャーを使ってみてます

@testing-library/user-event

__test__/App.test.tsx
import userEvent from "@testing-library/user-event";

@testing-library/user-event は、上述したように、
DOMに対するユーザーの操作を疑似的に再現してくれています。

__test__/App.test.tsx
// userインスタンスのセットアップ
const user = userEvent.setup();
__test__/App.test.tsx
        const countButtonElement = screen.getByRole("button")

        // userの操作を再現する
        // clickはasync関数なので、awaitする
        await user.click(countButtonElement)

くりっくしてくれます

テストコードはこんな感じなので、テストを実行してみます

c/work/react/my-react-ts-app$ pnpm run test

> my-react-ts-app@0.0.0 test c/work/react/my-react-ts-app
> vitest


 DEV  v2.1.2 c/work/react/my-react-ts-app

 ✓ __test__/App.test.tsx (3) 387ms
   ✓ tsx sample (3) 385ms
     ✓ viteとReactの画像が表示されていることを確認する
     ✓ use jest-dom sample
     ✓ use user-event sample

 Test Files  1 passed (1)
      Tests  3 passed (3)
   Start at  10:57:57
   Duration  93.69s (transform 822ms, setup 0ms, collect 36.01s, tests 387ms, environment 47.37s, prepare 7.85s)


 PASS  Waiting for file changes...
       press h to show help, press q to quit

やったー

これで超基本の部分の環境構築は完了したかなーと思います!

10
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?