Web系の知識
- Reactのプロジェクト作成コマンド
npm create vite@latest
Prettier
- ソースコードを綺麗にしてくれるコードフォーマッター
- 設定手順
- Prettier関連パッケージのインストール
-
npm install --save-dev prettier eslint-config-prettierを実行- eslint-config-prettier: ESLintとPrettierの設定の競合を防ぐ
-
Prettier設定ファイルの作成
- プロジェクトのルートディレクトリに
.prettierrcファイルを作成※コメントはコピー不可
{
"semi": true, // 文末にセミコロンを追加
"singleQuote": true, // シングルクォートを使用
"tabWidth": 2, // インデントのスペース数
"trailingComma": "es5", // 末尾のカンマをES5互換にする
"printWidth": 100, // 1行の最大文字数
"bracketSpacing": true, // オブジェクトリテラルの括弧間にスペースを入れる
"arrowParens": "avoid", // 可能な場合、アロー関数の括弧を省略
"endOfLine": "auto" // 改行コードを自動検出
}
ESlint
- JavaScript及びTypeScript等の静的解析ツール。導入により、単純な構文エラーやプロジェクト固有のコーディング規約を定義可能
useContext
- context側で↓書く理由
export const useAuth = () => {
const context = useContext(AuthContext);
if (context === undefined) {
throw new Error('useAuth must be used within an AuthProvider');
}
return context;
};
- 型安全と再利用性の向上
- もし
useAuth()がない場合、useContext(AuthContext)の戻り値はAuthContextType | undefiendなので、子コンポーネント側で、以下を毎回記述する必要がある
- もし
const auth = useContext(Authcontext);
if(!auth) {
throw new Error("AuthContext is not provided");
}
-
Provider外での誤使用を防止する
- React Contextは
<AuthProvider>でラップされていないコンポーネントでuseContext(Authcontext)を呼ぶとundefinedを返却するので、useAuth()でチェックしておけば、すぐにバグを検知可能
- React Contextは
-
実装の隠蔽(カプセル化)
- useAuth()を作っておくと、子コンポーネントはAuthContextの中身や構造を知らなくても使えるので、将来ReduxやGraphQLに変更しても、useAuth()の中身を変えるだけで済む
ブラウザのストレージ
- 考え方
- localStorage
- メリット
- 再ログイン不要。UXが良い
- シンプルで実装が楽
- デメリット
- 主導で削除しない限り、トークンが残る
- 公共PCでのログイン時などにリスク
- 個人アプリや社内ツール向き
- sessionStorage
- メリット
- ブラウザを閉じると自動ログアウト
- セキュリティが強い(管理画面向き)
- デメリット
- UXが悪くなる(要再ログイン)
- 複数タブでログイン状態が共有されない
useNavigate
- React Router v6で導入されたフックで、javascriptコードからプログラム的にページ遷移をおこなう
- 基本的な使い方
- const navigate = useNavigate();で関数を取得し、navigate("/path");のように引数に遷移先パスを指定する
- 履歴操作
- navigate(-1);とすると、ブラウザの戻るボタンのように1つ前のページに戻れる
- 履歴の置き換え
- navigate("/path, { replace: true });のように、オプションを指定すると、遷移先のページが履歴に残らなくなる(戻るボタンで戻れない)
- 値の受け渡し
- navigate("/path, { state: { data: "" } });のようにstateプロパティで遷移先にデータを渡すことも可能(useLocationフックで受け取る)
HTTPSTATUS
- 参考サイト
- HTTP 100番台 Informational(情報レスポンス)
- クライアントからのリクエストを受け入れ可能で、継続して処理されている状態
- HTTP 200番台 Success(成功レスポンス)
-
クライアントからリクエストがサーバーに送られ理解・受理された状態
HTTPステータスコード 説明 状態 100 Continue リクエスト継続可能 正常 101 Switching Protocol プロトコルの切替 正常 102 Processing 処理中 正常 200 OK リクエストが正常に処理できた 正常 201 Created リクエストが成功してリソースの作成が完了 正常 202 Accepted リクエストを受け取ったが処理はされていない 正常 203 Non-Authoritative Information リクエストが成功したものの、変換プロキシによって元のサーバーの200レスポンスからペイロードが変更された 正常 204 No Content リクエストに対して送信するコンテンツは無いがヘッダは有用である 正常 205 Reset Content クライアントにドキュメントビューをリセットするように指示 正常 206 Potential Content 要求された範囲のデータやリソースの一部分だけのリクエストが成功 正常 300 Multiple Choice リクエストに対して複数のレスポンスがあることを示す 正常 301 Moved Permanently 恒久的に移動する 正常 302 Found 一時的に移動する 正常 304 Not Modified 更新されていない 正常 400 Bad Request 一般的なクライアントエラー エラー 401 Unauthorized アクセス権が無い、または認証に失敗 エラー 402 Payment Required 料金の支払いをするまでリクエストを処理できない状態 エラー 403 Forbidden 閲覧権限が無いファイルやフォルダ エラー 404 Not Found Webページが見つからない エラー 405 Method Not Allowed 送信するクライアント側のメソッドが許可されていない エラー 406 Not Acceptable サーバ側が受付不能な値(ファイルの種類など)であり提供できない状態 エラー 407 Proxy Authentication Required プロキシサーバー経由で通信を行う際にプロキシサーバの認証情報が不足している エラー 408 Request Timeout リクエスト送信後のやり取りに時間が長すぎるため時間切れ エラー 409 Conflict サーバに既に存在しているデータが競合しているためリクエストを完了できない エラー 410 Gone ファイルが削除されたため、ほぼ永久的にWebページが存在しない エラー 411 Length Required Content-Lengthとはリクエストヘッダーに送るデータ容量が書いてある項目。サーバーの方でContent-Lengthヘッダーが無いためアクセスを拒否した エラー 412 Procondition Failed ヘッダで定義された前提条件が満たされていない場合にアクセス拒否される エラー 413 Payload Too Large ファイルをアップロードする際にサーバーで定めたファイル容量の上限を超えてしまった為アクセス拒否された エラー 414 URI Too Long 指定したURLが長すぎる エラー 415 Unsupported Media Type サーバーで許可していないリクエストの種類の為アクセス拒否された エラー 416 Range Not Satisfiable サーバーがリクエストされた範囲(容量)を提供できない エラー 417 Expectation Failed サーバーが拡張されたステータスコードを返却できない エラー 422 Unprocessable Entity WebDAVの拡張ステータスコード。リクエストは適正だが意味が異なるためサーバーが返却できない エラー 423 Locked WebDAVの拡張ステータスコード。リクエスト内容がロックされているためサーバーが返却できない エラー 500 Internal Server Error 何らかのサーバ内で起きたエラー エラー
テスト導入
- よく聞くJestではなく、Vitestの方が良いらしい
-
viteで作成したプロジェクトの為、引き継げる部分が多い
-
テストライブラリインストール
- React Testing Library(RTL)
- 参考サイト
- 特徴
- ユーザー主導のテスト:ボタンのクリックやテキストの入力など、実際の操作を試すことが可能
- 実装に依存しない:コンポーネントの内部構造を変更しても、UIが変わらなければテストが壊れにくい
- アクセシビリティを重視:
getByRoleやgetByTextなど、ユーザーが認識できる方法で要素を取得可能 - 実際のブラウザを使用せずにDOMを試せるツール(jsdomなど)を使用し、高速にテストを実行可能
npm i -D vitest jsdom @testing-library/react @testing-library/jest-dom @testing-library/user-event
-
package.jsonにscriptsを追加
typescript { "scripts": { "test": "vitest, "test:ui": "vitest --ui", "test:watch": "vitest --watch", "test:run": "vitest run", } } -
vite.config.tsにtestを追加
```typescript import { defineconfig } from 'vitest/config'; // fromを「vite」→「vitest/config」 import react from '@vitejs/plugin-react';
export default defineConfig({ plugins: [react()], test: { environment: 'jsdom', setupFiles: './src/tests/setup.ts', globals: true, css: true, }, }); ```
-
tsconfig.node.jsonのtypesにvitestを追加
-
"types": ["node"] → "types": ["node", "vitest"]
-
tsconfig.app.jsonのtypesを修正
-
"types": ["node", "vitest"] → "types": ["vitest/globals"]
-
src/tests/setup.tsを作成
typescript import '@testing-library/jest-dom';
vitest
- テストに関する関数
- vi.mock再入門
| モック方法 | 使う場面の例 | 主な特徴 |
|---|---|---|
| vi.fn() | 任意の関数をテスト対象に渡す場合 | シンプルなモック |
| vi.spyOn() | 既存のオブジェクトやグローバル関数を部分的にモック化する場合 | 元の実装をモックで置き換え可能 |
| vi.mock() | モジュール全体をモック化し、テスト対象から切り離す場合 | 高度な依存性切り離し、巻き上げ注意が必要。リセットしてもオリジナル実装に戻らない。 |
- vi.fn()
- vi.fn()はモック関数を生成するユーティリティ関数です。モック関数は自分自身が呼び出された回数や引数を記録します。モック関数を直接実行したり、テスト対象に渡して内部でどのように呼び出されるかを検証可能です。
import { vi } from "vitest"
const func = vi.fn(() => 0);
test(func); // テストしたい関数に、モック関数を渡す
expect(func).toHaveBeenCalled(); // モック関数が1回以上呼び出されないとテスト失敗
expect(func).toHaveBeenCalledWith(5); // 引数が5で呼び出されないとテスト失敗
import { vi } from "vitest";
const func = vi.fn(() => 0);
const mockedFunc = func.mockImplementation(() => 5); // 元の実装の代わりに、5を返却する関数
test(func); // テストしたい関数に、モック関数を渡す
expect(func).toHaveReturnedWith(5); // 0を返却するオリジナル実装ではなく、5を返すモック実装が呼び出される
- モックの履歴
- vi.fn()インスタンスは、以下の履歴を保存しています。
- モック関数が呼び出された回数
- モック関数に渡された引数
- モック関数が返却した値
-
意図通りにモック関数が呼び出されているかをexpectで評価します
-
vi.spyOn()
- vi.spyOn()は、オブジェクトのメソッドをモック関数に差し替えるユーティリティ関数です。下記の例では、cart.getApples関数をモック関数に差し替えています。 vi.spyOn()は、オブジェクトに内包される関数の振る舞いを監視するために使われます。 差し替えられた関数spyは、vi.fn()で生成されるモック関数と同じものです。モック関数か否かの判定はvi.isMockFunction関数を利用します。 vi.spyOn関数はwindowやconsoleなどのグローバルオブジェクトのモックにも使えます。
import { vi } from "vitest"
cont cart = {
getApples: () => 42,
}
const spy = vi.spyOn(cart, 'getApples').mockImplementation(() => 1);
- vi.mock()
-
vi.mock()はインポートパスをフックし、そのパスで呼び出されるモジュールすべてをモックします。
typescript import { Calculator } from './src/calculator.ts' vi.mock('./src/calculator.ts'); -
モック関数のクリア/リセット/リストア
| メソッド | 主な用途 | 呼出履歴のクリア | 実装のクリア | 元の実装に戻す | 使用対象 | 備考 |
|---|---|---|---|---|---|---|
| mockClear() | テストの使用状況(履歴)を初期化 | ✓ | × | × | vitest.fn() / spyOn() | |
| mockReset() | 履歴をクリアし、モック実装を削除する | ✓ | ✓ | × | vitest.fn() / spyOn() | |
| mockRestore() | 履歴をクリアし、モック実装をオリジナル関数に戻す | ✓ | ✓ | ✓ | spyOn()のみ |
- clear
- mockclearは、以下のように動作します
- モック関数の履歴をクリアする
- モック実装は維持する
test("モッククリアは実装を維持する", () => {
const func = vi.fn(() => 1);
const mockedFunc = func.mockImplementation(() => 2); // モック関数は2を返却
const result = mockedFunc();
expect(mockedFunc).toBeCalledTimes(1); // 呼び出された回数は1回
expect(result).toBe(2); // モック関数が呼び出されたので、戻り値は2
func.mockClear(); // モックをクリア
expect(mockedFunc).toBeCalledTimes(0); // 呼び出し回数がリセットされる
const result2 = func(); // 2回目の呼び出し
expect(mockedFunc).toBeCalledTimes(1); // 呼び出し回数が1回に戻る
expec(result2).toBe(2); // モック関数の実装は維持される
})
- reset
- mockResetは以下のように動作します。
- モック関数の履歴をクリアする
- モック実装を破棄し、undefinedに置き換える
test("モックリセットはモック実装を破棄する", () => {
const func = vi.fn(() => 1);
const mockedFunc = func.mockImplementation(() => 2);
mockedFunc.mockReset();
const result = mockedFunc();
expect(result).toBe(undefined); // モック実装が破棄されたため、undefinedが返却される
})
- restore
- mockRestoreは、以下のように動作します。
- モック関数の履歴をクリアする
- モック実装を、置き換える前のオリジナルの関数に戻す
test("モックリストアはオリジナルの実装に戻す", () => {
const func = vi.fn(() => 1); // オリジナルの関数は1を返却
const mockedFunc = func.mockImplementation(() => 2); // モック実装は2を返却
const result = mockedFunc();
expect(mockedFunc).toBeCalledTimes(1);
expect(result).toBe(2); // モック実装が呼び出されるため、2を返却
mockedFunc.mockRestore(); // モックをレストアする
expect(mockedFunc).toBeCalledTimes(0); // モック関数の履歴がリセットされる
const result2 = mockedFunc();
expect(result2).toBe(1); // モック関数の実装がオリジナルに戻るため、1が返却される
})
vitestのテストで使用可能なMathcer一覧
-
MemoryRouter
- ブラウザのURLバーと連動せず、メモリ内(メモリー上)に履歴を保存・管理するreact-router-domのルーターコンポーネント。URLに依存しないため、コンポーネントのテスト、React Native環境、又はシミュレーションされたページ遷移が必要な場面で主に使用される