1) 依存を入れる
# まだなら Vite React プロジェクト作成(TS前提)
npm create vite@latest my-app -- --template react-ts
cd my-app
# テスト用の依存
npm i -D vitest @testing-library/react @testing-library/user-event @testing-library/jest-dom jsdom
2) vite.config.ts に Vitest 設定
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
test: {
environment: 'jsdom', // DOMが必要なのでjsdom
setupFiles: './src/test/setup.ts',
css: true, // CSS importがあってもOKに
globals: true, // expect などをグローバルに(好み)
coverage: { reporter: ['text', 'html'] } // 任意
},
})
3) セットアップファイルを用意
src/test/setup.ts
import '@testing-library/jest-dom'
4) tsconfig.json の型サポート(念のため)
types に vitest/globals を追加(既にあればOK)。
{
"compilerOptions": {
"types": ["vitest/globals", "vite/client", "@testing-library/jest-dom"]
}
}
5) package.json のスクリプト
{
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
"preview": "vite preview",
"test": "vitest",
"test:ui": "vitest --ui",
"test:watch": "vitest --watch"
}
}
6) 動作確認用のサンプル(最小)
src/TypingWPM.tsx
import { useState } from 'react'
export default function TypingWPM() {
const [running, setRunning] = useState(false)
const [text, setText] = useState('')
const [secs, setSecs] = useState(0)
return (
<div>
<textarea
value={text}
onChange={e => setText(e.target.value)}
disabled={!running}
/>
<div>
<button onClick={() => setRunning(true)}>Start</button>
<button onClick={() => setRunning(false)}>Stop</button>
<button onClick={() => { setRunning(false); setText(''); setSecs(0) }}>
Reset
</button>
</div>
<p>Time: {secs}s</p>
<p>WPM: 0</p>
</div>
)
}
src/TypingWPM.test.tsx
import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import TypingWPM from './TypingWPM'
test('初期表示: ボタンがあり、入力は無効、Timeは0', () => {
render(<TypingWPM />)
expect(screen.getByRole('button', { name: /start/i })).toBeInTheDocument()
expect(screen.getByRole('button', { name: /stop/i })).toBeInTheDocument()
expect(screen.getByRole('button', { name: /reset/i })).toBeInTheDocument()
const textarea = screen.getByRole('textbox')
expect(textarea).toBeDisabled()
expect(screen.getByText(/time:\s*0s/i)).toBeInTheDocument()
})
7) 走らせる
npm run test
# または UI 付きで
npm run test:ui
8) タイマー系テストの準備(次で使う)
Vitest でフェイクタイマーを使う時:
import { vi, act } from 'vitest'
beforeEach(() => {
vi.useFakeTimers()
})
afterEach(() => {
vi.useRealTimers()
})
// 進める
act(() => { vi.advanceTimersByTime(1000) })
ここまで通ればTDDの土台完成。