import { jsx, jsxs, Fragment } from 'solid-jsx/jsx-runtime';

/*@jsxRuntime automatic @jsxImportSource solid-jsx*/
const toc = [{
  "depth": 1,
  "value": "Solid のテスト",
  "children": [{
    "depth": 2,
    "value": "テストのセットアップ",
    "children": [{
      "depth": 3,
      "value": "Jest を設定する",
      "children": [{
        "depth": 4,
        "value": "Jest と TypeScript (ts-jest)",
        "children": []
      }]
    }, {
      "depth": 3,
      "value": "uvu を設定する",
      "children": [{
        "depth": 4,
        "value": "Uvu と TypeScript (ts-uvu)",
        "children": []
      }, {
        "depth": 4,
        "value": "uvu のカバレッジレポート",
        "children": []
      }, {
        "depth": 4,
        "value": "Watch モード",
        "children": []
      }]
    }]
  }, {
    "depth": 2,
    "value": "テストのパターンとベストプラクティス",
    "children": [{
      "depth": 3,
      "value": "リアクティブな状態のテスト",
      "children": [{
        "depth": 4,
        "value": "Jest でのテスト",
        "children": []
      }, {
        "depth": 4,
        "value": "uvu でのテスト",
        "children": []
      }]
    }, {
      "depth": 3,
      "value": "ディレクティブのテスト",
      "children": [{
        "depth": 4,
        "value": "Jest でのテスト",
        "children": []
      }, {
        "depth": 4,
        "value": "uvu でのテスト",
        "children": []
      }]
    }, {
      "depth": 3,
      "value": "コンポーネントのテスト",
      "children": [{
        "depth": 4,
        "value": "Jest でのテスト",
        "children": []
      }, {
        "depth": 4,
        "value": "uvu でのテスト",
        "children": []
      }]
    }]
  }]
}];
function _createMdxContent(props) {
  const _components = Object.assign({
    h1: "h1",
    a: "a",
    p: "p",
    h2: "h2",
    ul: "ul",
    li: "li",
    h3: "h3",
    code: "code",
    h4: "h4",
    pre: "pre",
    span: "span",
    blockquote: "blockquote"
  }, props.components);
  return jsxs(Fragment, {
    children: [jsxs(_components.h1, {
      id: "solid-のテスト",
      children: [jsx(_components.a, {
        className: "header-anchor",
        href: "#solid-のテスト",
        children: "#"
      }), "Solid のテスト"]
    }), "\n", jsx(_components.p, {
      children: "Solid のコードを本番環境で使用するには、テストする必要があります。すべてを手動でテストしたくはないので、自動テストが必要です。このガイドでは、すべてのセットアップ方法と Solid コードのテストに役立ついくつかのパターンを説明します。"
    }), "\n", jsxs(_components.h2, {
      id: "テストのセットアップ",
      children: [jsx(_components.a, {
        className: "header-anchor",
        href: "#テストのセットアップ",
        children: "#"
      }), "テストのセットアップ"]
    }), "\n", jsx(_components.p, {
      children: "私たちは 2 つのテストランナーのサポートを提供しています:"
    }), "\n", jsxs(_components.ul, {
      children: ["\n", jsxs(_components.li, {
        children: ["\n", jsx(_components.p, {
          children: "jest - 多くの機能を持ち、非常によく知られています"
        }), "\n"]
      }), "\n", jsxs(_components.li, {
        children: ["\n", jsx(_components.p, {
          children: "uvu - 必要最低限のものだけをもたらします"
        }), "\n"]
      }), "\n"]
    }), "\n", jsxs(_components.p, {
      children: ["どちらも ", jsx(_components.a, {
        href: "https://github.com/solidjs/solid-testing-library",
        children: "solid-testing-library"
      }), " をベースにしており、", jsx(_components.a, {
        href: "https://testing-library.com/",
        children: "Testing Library"
      }), " を Solid に統合しています。テスティングライブラリは軽量なブラウザを模倣し、テストからそれを操作するための API を提供します。"]
    }), "\n", jsx(_components.p, {
      children: "Solid と Jest テスト用のスターターテンプレートが用意されています。これをベースにしてプロジェクトを作成するか、スクラッチのプロジェクトにスターターテンプレートをインストールし、その設定をプロジェクトにコピーすることをお勧めします。"
    }), "\n", jsxs(_components.p, {
      children: ["このテンプレートは、インストールに ", jsx(_components.a, {
        href: "https://github.com/Rich-Harris/degit",
        children: "degit"
      }), " ユーティリティを使用します。"]
    }), "\n", jsxs(_components.h3, {
      id: "jest-を設定する",
      children: [jsx(_components.a, {
        className: "header-anchor",
        href: "#jest-を設定する",
        children: "#"
      }), "Jest を設定する"]
    }), "\n", jsxs(_components.p, {
      children: ["Jest 統合は、Solid をブラウザとして使用できるようにする ", jsx(_components.a, {
        href: "https://github.com/solidjs/solid-jest",
        children: "solid-jest/preset/browser"
      }), " Jest 設定プリセットをベースにしています。これは、Solid コードを変換するために babel を使用します。"]
    }), "\n", jsxs(_components.p, {
      children: ["これは ", jsx(_components.a, {
        href: "https://github.com/testing-library/jest-dom",
        children: "jest-dom"
      }), " を使用して ", jsx(_components.code, {
        children: "expect"
      }), " を拡張し、テストを書くのに役立つ多くのカスタム マッチャーを使用します。"]
    }), "\n", jsxs(_components.h4, {
      id: "jest-と-typescript-ts-jest",
      children: [jsx(_components.a, {
        className: "header-anchor",
        href: "#jest-と-typescript-ts-jest",
        children: "#"
      }), "Jest と TypeScript (", jsx(_components.code, {
        children: "ts-jest"
      }), ")"]
    }), "\n", jsx(_components.pre, {
      children: jsxs(_components.code, {
        className: "hljs language-bash",
        children: ["$ npx degit solidjs/templates/ts-jest my-solid-project\n$ ", jsx(_components.span, {
          className: "hljs-built_in",
          children: "cd"
        }), " my-solid-project\n$ npm install ", jsx(_components.span, {
          className: "hljs-comment",
          children: "# もしくは pnpm install もしくは yarn install"
        }), "\n"]
      })
    }), "\n", jsxs(_components.p, {
      children: ["このテンプレートはテスト中にタイプチェックを行わないことに注意してください。IDE や ", jsx(_components.code, {
        children: "package.json"
      }), " にあるカスタム ", jsx(_components.code, {
        children: "tsc --noEmit"
      }), " スクリプトを使用して、このようなチェックをトリガーできます。"]
    }), "\n", jsxs(_components.h3, {
      id: "uvu-を設定する",
      children: [jsx(_components.a, {
        className: "header-anchor",
        href: "#uvu-を設定する",
        children: "#"
      }), "uvu を設定する"]
    }), "\n", jsxs(_components.p, {
      children: ["また、", jsx(_components.code, {
        children: "uvu"
      }), " のスターターテンプレートも提供しています。"]
    }), "\n", jsxs(_components.p, {
      children: ["このテンプレートには ", jsx(_components.a, {
        href: "https://www.npmjs.com/package/solid-dom-testing",
        children: "solid-dom-testing"
      }), " が含まれており、Testing Library で有用なアサーションを記述するのに役立ちます。"]
    }), "\n", jsxs(_components.h4, {
      id: "uvu-と-typescript-ts-uvu",
      children: [jsx(_components.a, {
        className: "header-anchor",
        href: "#uvu-と-typescript-ts-uvu",
        children: "#"
      }), "Uvu と TypeScript (", jsx(_components.code, {
        children: "ts-uvu"
      }), ")"]
    }), "\n", jsx(_components.pre, {
      children: jsxs(_components.code, {
        className: "hljs language-bash",
        children: ["$ npx degit solidjs/templates/ts-uvu my-solid-project\n$ ", jsx(_components.span, {
          className: "hljs-built_in",
          children: "cd"
        }), " my-solid-project\n$ npm install ", jsx(_components.span, {
          className: "hljs-comment",
          children: "# もしくは pnpm install もしくは yarn install"
        }), "\n"]
      })
    }), "\n", jsxs(_components.h4, {
      id: "uvu-のカバレッジレポート",
      children: [jsx(_components.a, {
        className: "header-anchor",
        href: "#uvu-のカバレッジレポート",
        children: "#"
      }), "uvu のカバレッジレポート"]
    }), "\n", jsxs(_components.blockquote, {
      children: ["\n", jsxs(_components.p, {
        children: ["残念ながら、", jsx(_components.a, {
          href: "https://github.com/babel/babel/issues/4289",
          children: "babelの制限"
        }), "により、トランスパイルされた JSX のソースマップ出力はできません。その結果、コンポーネントのカバレッジはゼロとなります。JSX でないコードでは動作します。"]
      }), "\n"]
    }), "\n", jsx(_components.p, {
      children: "テストのコードカバレッジを確認したい場合、uvu のお気に入りのツールは c8 です。インストールと設定のために、以下を実行します:"
    }), "\n", jsx(_components.pre, {
      children: jsxs(_components.code, {
        className: "hljs language-sh",
        children: ["> npm i --save-dev c8 ", jsx(_components.span, {
          className: "hljs-comment",
          children: "# もしくは yarn add -D もしくは pnpm"
        }), "\n> npm set-script ", jsx(_components.span, {
          className: "hljs-string",
          children: "\"test:coverage\""
        }), " ", jsx(_components.span, {
          className: "hljs-string",
          children: "\"c8 uvu -r solid-register\""
        }), "\n"]
      })
    }), "\n", jsxs(_components.p, {
      children: ["これで ", jsx(_components.code, {
        children: "npm run test:coverage"
      }), " を実行すると、テストのカバレッジが表示されるようになります。"]
    }), "\n", jsxs(_components.p, {
      children: ["HTML 形式のカバレッジレポートが欲しい場合は、", jsx(_components.code, {
        children: "c8"
      }), " の代わりに ", jsx(_components.code, {
        children: "c8 -r html"
      }), " を使って、html レポーターを有効にできます。"]
    }), "\n", jsxs(_components.h4, {
      id: "watch-モード",
      children: [jsx(_components.a, {
        className: "header-anchor",
        href: "#watch-モード",
        children: "#"
      }), "Watch モード"]
    }), "\n", jsxs(_components.p, {
      children: [jsx(_components.code, {
        children: "uvu"
      }), " はすぐに使用できるウォッチモードはありませんが、 ", jsx(_components.code, {
        children: "chokidar-cli"
      }), " を使用して同じことを行うことができます:"]
    }), "\n", jsx(_components.pre, {
      children: jsxs(_components.code, {
        className: "hljs language-sh",
        children: ["> npm i --save-dev chokidar-cli ", jsx(_components.span, {
          className: "hljs-comment",
          children: "# もしくは yarn add -D もしくは pnpm"
        }), "\n> npm set-script ", jsx(_components.span, {
          className: "hljs-string",
          children: "\"test:watch\""
        }), " ", jsx(_components.span, {
          className: "hljs-string",
          children: "\"chokidar src/**/*.ts src/**/*.tsx -c \\\"uvu -r solid-register\\\"\n# use .js/.jsx instead of .ts/.tsx\n"
        })]
      })
    }), "\n", jsxs(_components.p, {
      children: ["これで ", jsx(_components.code, {
        children: "npm run test:watch"
      }), " を実行すると、ファイルを変更するたびにテストが実行されるようになります。"]
    }), "\n", jsxs(_components.h2, {
      id: "テストのパターンとベストプラクティス",
      children: [jsx(_components.a, {
        className: "header-anchor",
        href: "#テストのパターンとベストプラクティス",
        children: "#"
      }), "テストのパターンとベストプラクティス"]
    }), "\n", jsx(_components.p, {
      children: "さて、テストツールのインストールが完了したら、次はそれらを使ってみましょう。これを簡単にするため、Solid はいくつかのすばらしいパターンをサポートしています。"
    }), "\n", jsxs(_components.h3, {
      id: "リアクティブな状態のテスト",
      children: [jsx(_components.a, {
        className: "header-anchor",
        href: "#リアクティブな状態のテスト",
        children: "#"
      }), "リアクティブな状態のテスト"]
    }), "\n", jsxs(_components.p, {
      children: ["メンテナンスを容易にするため、あるいは複数のビューをサポートできるようにするため、状態の一部をコンポーネントから分離しておきたい場合があります。この場合、テストの対象となるインターフェイスは状態そのものです。", jsx(_components.a, {
        href: "https://www.solidjs.com/docs/latest/api#createroot",
        children: "リアクティブルート"
      }), "の外では、状態は追跡されず、更新しても Effect や Memo がトリガーされないことに注意してください。"]
    }), "\n", jsxs(_components.p, {
      children: ["また、Effect は非同期でトリガーされるので、最終的な Effect にアサーションをラップするのに役立ちます。また、複数の変更に対する一連の Effect を観察するには、", jsx(_components.code, {
        children: "createRoot"
      }), " から必要なツールを返して、非同期のテスト関数で実行すると便利です（", jsx(_components.code, {
        children: "createRoot"
      }), " 自体は ", jsx(_components.code, {
        children: "async"
      }), " 関数を受け取ることができないので）。"]
    }), "\n", jsxs(_components.p, {
      children: ["例として、", jsx(_components.a, {
        href: "https://www.solidjs.com/examples/todos",
        children: "ToDo のサンプル"
      }), "にある ", jsx(_components.code, {
        children: "createLocalStorage"
      }), " をテストしてみましょう:"]
    }), "\n", jsx(_components.pre, {
      children: jsxs(_components.code, {
        className: "hljs language-ts",
        children: [jsx(_components.span, {
          className: "hljs-keyword",
          children: "import"
        }), " { createEffect } ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "from"
        }), " ", jsx(_components.span, {
          className: "hljs-string",
          children: "\"solid-js\""
        }), ";\n", jsx(_components.span, {
          className: "hljs-keyword",
          children: "import"
        }), " { createStore, ", jsx(_components.span, {
          className: "hljs-title class_",
          children: "Store"
        }), ", ", jsx(_components.span, {
          className: "hljs-title class_",
          children: "SetStoreFunction"
        }), " } ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "from"
        }), " ", jsx(_components.span, {
          className: "hljs-string",
          children: "\"solid-js/store\""
        }), ";\n\n", jsx(_components.span, {
          className: "hljs-keyword",
          children: "export"
        }), " ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "function"
        }), " createLocalStore<T>(\n  ", jsx(_components.span, {
          className: "hljs-attr",
          children: "initState"
        }), ": T\n): [", jsx(_components.span, {
          className: "hljs-title class_",
          children: "Store"
        }), "<T>, ", jsx(_components.span, {
          className: "hljs-title class_",
          children: "SetStoreFunction"
        }), "<T>] {\n  ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "const"
        }), " [state, setState] = ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "createStore"
        }), "(initState);\n  ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "if"
        }), " (", jsx(_components.span, {
          className: "hljs-variable language_",
          children: "localStorage"
        }), ".", jsx(_components.span, {
          className: "hljs-property",
          children: "todos"
        }), ") ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "setState"
        }), "(", jsx(_components.span, {
          className: "hljs-title class_",
          children: "JSON"
        }), ".", jsx(_components.span, {
          className: "hljs-title function_",
          children: "parse"
        }), "(", jsx(_components.span, {
          className: "hljs-variable language_",
          children: "localStorage"
        }), ".", jsx(_components.span, {
          className: "hljs-property",
          children: "todos"
        }), "));\n  ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "createEffect"
        }), "(", jsx(_components.span, {
          className: "hljs-function",
          children: "() =>"
        }), " (", jsx(_components.span, {
          className: "hljs-variable language_",
          children: "localStorage"
        }), ".", jsx(_components.span, {
          className: "hljs-property",
          children: "todos"
        }), " = ", jsx(_components.span, {
          className: "hljs-title class_",
          children: "JSON"
        }), ".", jsx(_components.span, {
          className: "hljs-title function_",
          children: "stringify"
        }), "(state)));\n  ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "return"
        }), " [state, setState];\n}\n"]
      })
    }), "\n", jsxs(_components.p, {
      children: ["TODO コンポーネントを作成する代わりに、このモデルを単独でテストできます。その際、1. リアクティブな変更は ", jsx(_components.code, {
        children: "render"
      }), " または ", jsx(_components.code, {
        children: "createRoot"
      }), " によって提供される追跡コンテキストがある場合のみ動作すること、2. 非同期であるが ", jsx(_components.code, {
        children: "createEffect"
      }), " によってそれをキャッチできること、を念頭に置く必要があります。", jsx(_components.code, {
        children: "createRoot"
      }), " を使用すると、手動で廃棄のトリガーをできるという利点があります:"]
    }), "\n", jsxs(_components.h4, {
      id: "jest-でのテスト",
      children: [jsx(_components.a, {
        className: "header-anchor",
        href: "#jest-でのテスト",
        children: "#"
      }), "Jest でのテスト"]
    }), "\n", jsx(_components.pre, {
      children: jsxs(_components.code, {
        className: "hljs language-ts",
        children: [jsx(_components.span, {
          className: "hljs-keyword",
          children: "import"
        }), " { createLocalStore } ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "from"
        }), " ", jsx(_components.span, {
          className: "hljs-string",
          children: "\"./main.tsx\""
        }), ";\n", jsx(_components.span, {
          className: "hljs-keyword",
          children: "import"
        }), " { createRoot, createEffect } ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "from"
        }), " ", jsx(_components.span, {
          className: "hljs-string",
          children: "\"solid-js\""
        }), ";\n\n", jsx(_components.span, {
          className: "hljs-title function_",
          children: "describe"
        }), "(", jsx(_components.span, {
          className: "hljs-string",
          children: "\"createLocalStore\""
        }), ", ", jsx(_components.span, {
          className: "hljs-function",
          children: "() =>"
        }), " {\n  ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "beforeEach"
        }), "(", jsx(_components.span, {
          className: "hljs-function",
          children: "() =>"
        }), " {\n    ", jsx(_components.span, {
          className: "hljs-variable language_",
          children: "localStorage"
        }), ".", jsx(_components.span, {
          className: "hljs-title function_",
          children: "removeItem"
        }), "(", jsx(_components.span, {
          className: "hljs-string",
          children: "\"todos\""
        }), ");\n  });\n\n  ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "const"
        }), " initialState = {\n    ", jsx(_components.span, {
          className: "hljs-attr",
          children: "todos"
        }), ": [],\n    ", jsx(_components.span, {
          className: "hljs-attr",
          children: "newTitle"
        }), ": ", jsx(_components.span, {
          className: "hljs-string",
          children: "\"\""
        }), ",\n  };\n\n  ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "test"
        }), "(", jsx(_components.span, {
          className: "hljs-string",
          children: "\"既存の状態を localStorage から読み取る\""
        }), ", ", jsx(_components.span, {
          className: "hljs-function",
          children: "() =>"
        }), "\n    ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "createRoot"
        }), "(", jsxs(_components.span, {
          className: "hljs-function",
          children: ["(", jsx(_components.span, {
            className: "hljs-params",
            children: "dispose"
          }), ") =>"]
        }), " {\n      ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "const"
        }), " savedState = { ", jsx(_components.span, {
          className: "hljs-attr",
          children: "todos"
        }), ": [], ", jsx(_components.span, {
          className: "hljs-attr",
          children: "newTitle"
        }), ": ", jsx(_components.span, {
          className: "hljs-string",
          children: "\"saved\""
        }), " };\n      ", jsx(_components.span, {
          className: "hljs-variable language_",
          children: "localStorage"
        }), ".", jsx(_components.span, {
          className: "hljs-title function_",
          children: "setItem"
        }), "(", jsx(_components.span, {
          className: "hljs-string",
          children: "\"todos\""
        }), ", ", jsx(_components.span, {
          className: "hljs-title class_",
          children: "JSON"
        }), ".", jsx(_components.span, {
          className: "hljs-title function_",
          children: "stringify"
        }), "(savedState));\n      ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "const"
        }), " [state] = ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "createLocalStore"
        }), "(initialState);\n      ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "expect"
        }), "(state).", jsx(_components.span, {
          className: "hljs-title function_",
          children: "toEqual"
        }), "(savedState);\n      ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "dispose"
        }), "();\n    }));\n\n  ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "test"
        }), "(", jsx(_components.span, {
          className: "hljs-string",
          children: "\"新しい状態を localStorage に格納する\""
        }), ", ", jsx(_components.span, {
          className: "hljs-function",
          children: "() =>"
        }), "\n    ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "createRoot"
        }), "(", jsxs(_components.span, {
          className: "hljs-function",
          children: ["(", jsx(_components.span, {
            className: "hljs-params",
            children: "dispose"
          }), ") =>"]
        }), " {\n      ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "const"
        }), " [state, setState] = ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "createLocalStore"
        }), "(initialState);\n      ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "setState"
        }), "(", jsx(_components.span, {
          className: "hljs-string",
          children: "\"newTitle\""
        }), ", ", jsx(_components.span, {
          className: "hljs-string",
          children: "\"updated\""
        }), ");\n      ", jsx(_components.span, {
          className: "hljs-comment",
          children: "// Effect をキャッチするため、Effect を使う"
        }), "\n      ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "return"
        }), " ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "new"
        }), " ", jsx(_components.span, {
          className: "hljs-title class_",
          children: "Promise"
        }), "<", jsx(_components.span, {
          className: "hljs-built_in",
          children: "void"
        }), ">(", jsxs(_components.span, {
          className: "hljs-function",
          children: ["(", jsx(_components.span, {
            className: "hljs-params",
            children: "resolve"
          }), ") =>"]
        }), "\n        ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "createEffect"
        }), "(", jsx(_components.span, {
          className: "hljs-function",
          children: "() =>"
        }), " {\n          ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "expect"
        }), "(", jsx(_components.span, {
          className: "hljs-title class_",
          children: "JSON"
        }), ".", jsx(_components.span, {
          className: "hljs-title function_",
          children: "parse"
        }), "(", jsx(_components.span, {
          className: "hljs-variable language_",
          children: "localStorage"
        }), ".", jsx(_components.span, {
          className: "hljs-property",
          children: "todos"
        }), " || ", jsx(_components.span, {
          className: "hljs-string",
          children: "\"\""
        }), ")).", jsx(_components.span, {
          className: "hljs-title function_",
          children: "toEqual"
        }), "({\n            ", jsx(_components.span, {
          className: "hljs-attr",
          children: "todos"
        }), ": [],\n            ", jsx(_components.span, {
          className: "hljs-attr",
          children: "newTitle"
        }), ": ", jsx(_components.span, {
          className: "hljs-string",
          children: "\"updated\""
        }), ",\n          });\n          ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "dispose"
        }), "();\n          ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "resolve"
        }), "();\n        })\n      );\n    }));\n\n  ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "test"
        }), "(", jsx(_components.span, {
          className: "hljs-string",
          children: "\"状態を複数回更新する\""
        }), ", ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "async"
        }), " () => {\n    ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "const"
        }), " { dispose, setState } = ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "createRoot"
        }), "(", jsxs(_components.span, {
          className: "hljs-function",
          children: ["(", jsx(_components.span, {
            className: "hljs-params",
            children: "dispose"
          }), ") =>"]
        }), " {\n      ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "const"
        }), " [state, setState] = ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "createLocalStore"
        }), "(initialState);\n      ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "return"
        }), " { dispose, setState };\n    });\n    ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "setState"
        }), "(", jsx(_components.span, {
          className: "hljs-string",
          children: "\"newTitle\""
        }), ", ", jsx(_components.span, {
          className: "hljs-string",
          children: "\"first\""
        }), ");\n    ", jsx(_components.span, {
          className: "hljs-comment",
          children: "// すべての Effect を解決するため 1 ティック待つ"
        }), "\n    ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "await"
        }), " ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "new"
        }), " ", jsx(_components.span, {
          className: "hljs-title class_",
          children: "Promise"
        }), "(", jsxs(_components.span, {
          className: "hljs-function",
          children: ["(", jsx(_components.span, {
            className: "hljs-params",
            children: "done"
          }), ") =>"]
        }), " ", jsx(_components.span, {
          className: "hljs-built_in",
          children: "setTimeout"
        }), "(done, ", jsx(_components.span, {
          className: "hljs-number",
          children: "0"
        }), "));\n    ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "expect"
        }), "(", jsx(_components.span, {
          className: "hljs-title class_",
          children: "JSON"
        }), ".", jsx(_components.span, {
          className: "hljs-title function_",
          children: "parse"
        }), "(", jsx(_components.span, {
          className: "hljs-variable language_",
          children: "localStorage"
        }), ".", jsx(_components.span, {
          className: "hljs-property",
          children: "todos"
        }), " || ", jsx(_components.span, {
          className: "hljs-string",
          children: "\"\""
        }), ")).", jsx(_components.span, {
          className: "hljs-title function_",
          children: "toEqual"
        }), "({\n      ", jsx(_components.span, {
          className: "hljs-attr",
          children: "todos"
        }), ": [],\n      ", jsx(_components.span, {
          className: "hljs-attr",
          children: "newTitle"
        }), ": ", jsx(_components.span, {
          className: "hljs-string",
          children: "\"first\""
        }), ",\n    });\n    ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "setState"
        }), "(", jsx(_components.span, {
          className: "hljs-string",
          children: "\"newTitle\""
        }), ", ", jsx(_components.span, {
          className: "hljs-string",
          children: "\"second\""
        }), ");\n    ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "await"
        }), " ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "new"
        }), " ", jsx(_components.span, {
          className: "hljs-title class_",
          children: "Promise"
        }), "(", jsxs(_components.span, {
          className: "hljs-function",
          children: ["(", jsx(_components.span, {
            className: "hljs-params",
            children: "done"
          }), ") =>"]
        }), " ", jsx(_components.span, {
          className: "hljs-built_in",
          children: "setTimeout"
        }), "(done, ", jsx(_components.span, {
          className: "hljs-number",
          children: "0"
        }), "));\n    ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "expect"
        }), "(", jsx(_components.span, {
          className: "hljs-title class_",
          children: "JSON"
        }), ".", jsx(_components.span, {
          className: "hljs-title function_",
          children: "parse"
        }), "(", jsx(_components.span, {
          className: "hljs-variable language_",
          children: "localStorage"
        }), ".", jsx(_components.span, {
          className: "hljs-property",
          children: "todos"
        }), " || ", jsx(_components.span, {
          className: "hljs-string",
          children: "\"\""
        }), ")).", jsx(_components.span, {
          className: "hljs-title function_",
          children: "toEqual"
        }), "({\n      ", jsx(_components.span, {
          className: "hljs-attr",
          children: "todos"
        }), ": [],\n      ", jsx(_components.span, {
          className: "hljs-attr",
          children: "newTitle"
        }), ": ", jsx(_components.span, {
          className: "hljs-string",
          children: "\"first\""
        }), ",\n    });\n    ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "dispose"
        }), "();\n  });\n});\n"]
      })
    }), "\n", jsxs(_components.h4, {
      id: "uvu-でのテスト",
      children: [jsx(_components.a, {
        className: "header-anchor",
        href: "#uvu-でのテスト",
        children: "#"
      }), "uvu でのテスト"]
    }), "\n", jsx(_components.pre, {
      children: jsxs(_components.code, {
        className: "hljs language-ts",
        children: [jsx(_components.span, {
          className: "hljs-keyword",
          children: "import"
        }), " { createLocalStore } ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "from"
        }), " ", jsx(_components.span, {
          className: "hljs-string",
          children: "\"./main\""
        }), ";\n", jsx(_components.span, {
          className: "hljs-keyword",
          children: "import"
        }), " { suite } ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "from"
        }), " ", jsx(_components.span, {
          className: "hljs-string",
          children: "\"uvu\""
        }), ";\n", jsx(_components.span, {
          className: "hljs-keyword",
          children: "import"
        }), " * ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "as"
        }), " assert ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "from"
        }), " ", jsx(_components.span, {
          className: "hljs-string",
          children: "\"uvu/assert\""
        }), ";\n", jsx(_components.span, {
          className: "hljs-keyword",
          children: "import"
        }), " { createEffect, createRoot } ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "from"
        }), " ", jsx(_components.span, {
          className: "hljs-string",
          children: "\"solid-js\""
        }), ";\n\n", jsx(_components.span, {
          className: "hljs-keyword",
          children: "const"
        }), " todoTest = ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "suite"
        }), "(", jsx(_components.span, {
          className: "hljs-string",
          children: "\"createLocalStore\""
        }), ");\n\ntodoTest.", jsx(_components.span, {
          className: "hljs-property",
          children: "before"
        }), ".", jsx(_components.span, {
          className: "hljs-title function_",
          children: "each"
        }), "(", jsx(_components.span, {
          className: "hljs-function",
          children: "() =>"
        }), " {\n  ", jsx(_components.span, {
          className: "hljs-variable language_",
          children: "localStorage"
        }), ".", jsx(_components.span, {
          className: "hljs-title function_",
          children: "removeItem"
        }), "(", jsx(_components.span, {
          className: "hljs-string",
          children: "\"todos\""
        }), ");\n});\n\n", jsx(_components.span, {
          className: "hljs-keyword",
          children: "const"
        }), " initialState = {\n  ", jsx(_components.span, {
          className: "hljs-attr",
          children: "todos"
        }), ": [],\n  ", jsx(_components.span, {
          className: "hljs-attr",
          children: "newTitle"
        }), ": ", jsx(_components.span, {
          className: "hljs-string",
          children: "\"\""
        }), ",\n};\n\n", jsx(_components.span, {
          className: "hljs-title function_",
          children: "todoTest"
        }), "(", jsx(_components.span, {
          className: "hljs-string",
          children: "\"既存の状態を localStorage から読み取る\""
        }), ", ", jsx(_components.span, {
          className: "hljs-function",
          children: "() =>"
        }), "\n  ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "createRoot"
        }), "(", jsxs(_components.span, {
          className: "hljs-function",
          children: ["(", jsx(_components.span, {
            className: "hljs-params",
            children: "dispose"
          }), ") =>"]
        }), " {\n    ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "const"
        }), " savedState = { ", jsx(_components.span, {
          className: "hljs-attr",
          children: "todos"
        }), ": [], ", jsx(_components.span, {
          className: "hljs-attr",
          children: "newTitle"
        }), ": ", jsx(_components.span, {
          className: "hljs-string",
          children: "\"saved\""
        }), " };\n    ", jsx(_components.span, {
          className: "hljs-variable language_",
          children: "localStorage"
        }), ".", jsx(_components.span, {
          className: "hljs-title function_",
          children: "setItem"
        }), "(", jsx(_components.span, {
          className: "hljs-string",
          children: "\"todos\""
        }), ", ", jsx(_components.span, {
          className: "hljs-title class_",
          children: "JSON"
        }), ".", jsx(_components.span, {
          className: "hljs-title function_",
          children: "stringify"
        }), "(savedState));\n    ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "const"
        }), " [state] = ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "createLocalStore"
        }), "(initialState);\n    assert.", jsx(_components.span, {
          className: "hljs-title function_",
          children: "equal"
        }), "(state, savedState);\n    ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "dispose"
        }), "();\n  })\n);\n\n", jsx(_components.span, {
          className: "hljs-title function_",
          children: "todoTest"
        }), "(", jsx(_components.span, {
          className: "hljs-string",
          children: "\"新しい状態を localStorage に格納する\""
        }), ", ", jsx(_components.span, {
          className: "hljs-function",
          children: "() =>"
        }), "\n  ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "createRoot"
        }), "(", jsxs(_components.span, {
          className: "hljs-function",
          children: ["(", jsx(_components.span, {
            className: "hljs-params",
            children: "dispose"
          }), ") =>"]
        }), " {\n    ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "const"
        }), " [_, setState] = ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "createLocalStore"
        }), "(initialState);\n    ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "setState"
        }), "(", jsx(_components.span, {
          className: "hljs-string",
          children: "\"newTitle\""
        }), ", ", jsx(_components.span, {
          className: "hljs-string",
          children: "\"updated\""
        }), ");\n    ", jsx(_components.span, {
          className: "hljs-comment",
          children: "// Effect をキャッチするため、Effect が必要"
        }), "\n    ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "return"
        }), " ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "new"
        }), " ", jsx(_components.span, {
          className: "hljs-title class_",
          children: "Promise"
        }), "<", jsx(_components.span, {
          className: "hljs-built_in",
          children: "void"
        }), ">(", jsxs(_components.span, {
          className: "hljs-function",
          children: ["(", jsx(_components.span, {
            className: "hljs-params",
            children: "resolve"
          }), ") =>"]
        }), "\n      ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "createEffect"
        }), "(", jsx(_components.span, {
          className: "hljs-function",
          children: "() =>"
        }), " {\n        assert.", jsx(_components.span, {
          className: "hljs-title function_",
          children: "equal"
        }), "(", jsx(_components.span, {
          className: "hljs-title class_",
          children: "JSON"
        }), ".", jsx(_components.span, {
          className: "hljs-title function_",
          children: "parse"
        }), "(", jsx(_components.span, {
          className: "hljs-variable language_",
          children: "localStorage"
        }), ".", jsx(_components.span, {
          className: "hljs-property",
          children: "todos"
        }), " || ", jsx(_components.span, {
          className: "hljs-string",
          children: "\"\""
        }), "), {\n          ", jsx(_components.span, {
          className: "hljs-attr",
          children: "todos"
        }), ": [],\n          ", jsx(_components.span, {
          className: "hljs-attr",
          children: "newTitle"
        }), ": ", jsx(_components.span, {
          className: "hljs-string",
          children: "\"updated\""
        }), ",\n        });\n        ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "dispose"
        }), "();\n        ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "resolve"
        }), "();\n      })\n    );\n  })\n);\n\ntodoTest.", jsx(_components.span, {
          className: "hljs-title function_",
          children: "run"
        }), "();\n"]
      })
    }), "\n", jsxs(_components.h3, {
      id: "ディレクティブのテスト",
      children: [jsx(_components.a, {
        className: "header-anchor",
        href: "#ディレクティブのテスト",
        children: "#"
      }), "ディレクティブのテスト"]
    }), "\n", jsxs(_components.p, {
      children: [jsx(_components.a, {
        href: "https://www.solidjs.com/docs/latest/api#use%3A___",
        children: "ディレクティブ"
      }), "は再利用可能な方法で参照を使用できるようにします。これらは基本的に ", jsx(_components.code, {
        children: "(ref: HTMLElement, data: Accessor<any>) => void"
      }), " というパターンに従った関数です。", jsx(_components.a, {
        href: "https://www.solidjs.com/tutorial/bindings_directives?solved",
        children: "ディレクティブのチュートリアル"
      }), "では、アクセサーの引数にラップされたコールバックを呼び出す ", jsx(_components.code, {
        children: "clickOutside"
      }), " ディレクティブを定義しています。"]
    }), "\n", jsx(_components.p, {
      children: "コンポーネントを作成し、そこでディレクティブを使用することもできますが、その場合はディレクティブを直接テストするのではなく、ディレクティブの使用をテストすることになります。マウントされたノードとアクセサーを提供することで、ディレクティブの外面をテストする方がより簡単です:"
    }), "\n", jsxs(_components.h4, {
      id: "jest-でのテスト-1",
      children: [jsx(_components.a, {
        className: "header-anchor",
        href: "#jest-でのテスト-1",
        children: "#"
      }), "Jest でのテスト"]
    }), "\n", jsx(_components.pre, {
      children: jsxs(_components.code, {
        className: "hljs language-ts",
        children: [jsx(_components.span, {
          className: "hljs-comment",
          children: "// click-outside.test.ts"
        }), "\n", jsx(_components.span, {
          className: "hljs-keyword",
          children: "import"
        }), " clickOutside ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "from"
        }), " ", jsx(_components.span, {
          className: "hljs-string",
          children: "\"click-outside\""
        }), ";\n", jsx(_components.span, {
          className: "hljs-keyword",
          children: "import"
        }), " { createRoot } ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "from"
        }), " ", jsx(_components.span, {
          className: "hljs-string",
          children: "\"solid-js\""
        }), ";\n", jsx(_components.span, {
          className: "hljs-keyword",
          children: "import"
        }), " { fireEvent } ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "from"
        }), " ", jsx(_components.span, {
          className: "hljs-string",
          children: "\"solid-testing-library\""
        }), ";\n\n", jsx(_components.span, {
          className: "hljs-title function_",
          children: "describe"
        }), "(", jsx(_components.span, {
          className: "hljs-string",
          children: "\"clickOutside\""
        }), ", ", jsx(_components.span, {
          className: "hljs-function",
          children: "() =>"
        }), " {\n  ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "const"
        }), " ref = ", jsx(_components.span, {
          className: "hljs-variable language_",
          children: "document"
        }), ".", jsx(_components.span, {
          className: "hljs-title function_",
          children: "createElement"
        }), "(", jsx(_components.span, {
          className: "hljs-string",
          children: "\"div\""
        }), ");\n\n  ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "beforeAll"
        }), "(", jsx(_components.span, {
          className: "hljs-function",
          children: "() =>"
        }), " {\n    ", jsx(_components.span, {
          className: "hljs-variable language_",
          children: "document"
        }), ".", jsx(_components.span, {
          className: "hljs-property",
          children: "body"
        }), ".", jsx(_components.span, {
          className: "hljs-title function_",
          children: "appendChild"
        }), "(ref);\n  });\n\n  ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "afterAll"
        }), "(", jsx(_components.span, {
          className: "hljs-function",
          children: "() =>"
        }), " {\n    ", jsx(_components.span, {
          className: "hljs-variable language_",
          children: "document"
        }), ".", jsx(_components.span, {
          className: "hljs-property",
          children: "body"
        }), ".", jsx(_components.span, {
          className: "hljs-title function_",
          children: "removeChild"
        }), "(ref);\n  });\n\n  ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "test"
        }), "(", jsx(_components.span, {
          className: "hljs-string",
          children: "\"外側のクリックでトリガーされる\""
        }), ", ", jsx(_components.span, {
          className: "hljs-function",
          children: "() =>"
        }), "\n    ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "createRoot"
        }), "(\n      ", jsxs(_components.span, {
          className: "hljs-function",
          children: ["(", jsx(_components.span, {
            className: "hljs-params",
            children: "dispose"
          }), ") =>"]
        }), "\n        ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "new"
        }), " ", jsx(_components.span, {
          className: "hljs-title class_",
          children: "Promise"
        }), "<", jsx(_components.span, {
          className: "hljs-built_in",
          children: "void"
        }), ">(", jsxs(_components.span, {
          className: "hljs-function",
          children: ["(", jsx(_components.span, {
            className: "hljs-params",
            children: "resolve"
          }), ") =>"]
        }), " {\n          ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "let"
        }), " clickedOutside = ", jsx(_components.span, {
          className: "hljs-literal",
          children: "false"
        }), ";\n          ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "clickOutside"
        }), "(ref, ", jsx(_components.span, {
          className: "hljs-function",
          children: "() =>"
        }), " ", jsx(_components.span, {
          className: "hljs-function",
          children: "() =>"
        }), " {\n            clickedOutside = ", jsx(_components.span, {
          className: "hljs-literal",
          children: "true"
        }), ";\n          });\n          ", jsx(_components.span, {
          className: "hljs-variable language_",
          children: "document"
        }), ".", jsx(_components.span, {
          className: "hljs-property",
          children: "body"
        }), ".", jsx(_components.span, {
          className: "hljs-title function_",
          children: "addEventListener"
        }), "(", jsx(_components.span, {
          className: "hljs-string",
          children: "\"click\""
        }), ", ", jsx(_components.span, {
          className: "hljs-function",
          children: "() =>"
        }), " {\n            ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "expect"
        }), "(clickedOutside).", jsx(_components.span, {
          className: "hljs-title function_",
          children: "toBeTruthy"
        }), "();\n            ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "dispose"
        }), "();\n            ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "resolve"
        }), "();\n          });\n          fireEvent.", jsx(_components.span, {
          className: "hljs-title function_",
          children: "click"
        }), "(", jsx(_components.span, {
          className: "hljs-variable language_",
          children: "document"
        }), ".", jsx(_components.span, {
          className: "hljs-property",
          children: "body"
        }), ");\n        })\n    ));\n\n  ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "test"
        }), "(", jsx(_components.span, {
          className: "hljs-string",
          children: "\"内側のクリックではトリガーされない\""
        }), ", ", jsx(_components.span, {
          className: "hljs-function",
          children: "() =>"
        }), "\n    ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "createRoot"
        }), "(\n      ", jsxs(_components.span, {
          className: "hljs-function",
          children: ["(", jsx(_components.span, {
            className: "hljs-params",
            children: "dispose"
          }), ") =>"]
        }), "\n        ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "new"
        }), " ", jsx(_components.span, {
          className: "hljs-title class_",
          children: "Promise"
        }), "<", jsx(_components.span, {
          className: "hljs-built_in",
          children: "void"
        }), ">(", jsxs(_components.span, {
          className: "hljs-function",
          children: ["(", jsx(_components.span, {
            className: "hljs-params",
            children: "resolve"
          }), ") =>"]
        }), " {\n          ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "let"
        }), " clickedOutside = ", jsx(_components.span, {
          className: "hljs-literal",
          children: "false"
        }), ";\n          ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "clickOutside"
        }), "(ref, ", jsx(_components.span, {
          className: "hljs-function",
          children: "() =>"
        }), " ", jsx(_components.span, {
          className: "hljs-function",
          children: "() =>"
        }), " {\n            clickedOutside = ", jsx(_components.span, {
          className: "hljs-literal",
          children: "true"
        }), ";\n          });\n          ref.", jsx(_components.span, {
          className: "hljs-title function_",
          children: "addEventListener"
        }), "(", jsx(_components.span, {
          className: "hljs-string",
          children: "\"click\""
        }), ", ", jsx(_components.span, {
          className: "hljs-function",
          children: "() =>"
        }), " {\n            ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "expect"
        }), "(clickedOutside).", jsx(_components.span, {
          className: "hljs-title function_",
          children: "toBeFalsy"
        }), "();\n            ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "dispose"
        }), "();\n            ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "resolve"
        }), "();\n          });\n          fireEvent.", jsx(_components.span, {
          className: "hljs-title function_",
          children: "click"
        }), "(ref);\n        })\n    ));\n});\n"]
      })
    }), "\n", jsxs(_components.h4, {
      id: "uvu-でのテスト-1",
      children: [jsx(_components.a, {
        className: "header-anchor",
        href: "#uvu-でのテスト-1",
        children: "#"
      }), "uvu でのテスト"]
    }), "\n", jsx(_components.pre, {
      children: jsxs(_components.code, {
        className: "hljs language-ts",
        children: [jsx(_components.span, {
          className: "hljs-comment",
          children: "// click-outside.test.ts"
        }), "\n", jsx(_components.span, {
          className: "hljs-keyword",
          children: "import"
        }), " clickOutside ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "from"
        }), " ", jsx(_components.span, {
          className: "hljs-string",
          children: "\"click-outside.tsx\""
        }), ";\n", jsx(_components.span, {
          className: "hljs-keyword",
          children: "import"
        }), " { createRoot } ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "from"
        }), " ", jsx(_components.span, {
          className: "hljs-string",
          children: "\"solid-js\""
        }), ";\n", jsx(_components.span, {
          className: "hljs-keyword",
          children: "import"
        }), " { fireEvent } ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "from"
        }), " ", jsx(_components.span, {
          className: "hljs-string",
          children: "\"solid-testing-library\""
        }), ";\n\n", jsx(_components.span, {
          className: "hljs-keyword",
          children: "const"
        }), " clickTest = ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "suite"
        }), "(", jsx(_components.span, {
          className: "hljs-string",
          children: "\"clickOutside\""
        }), ");\n\n", jsx(_components.span, {
          className: "hljs-keyword",
          children: "const"
        }), " ref = ", jsx(_components.span, {
          className: "hljs-variable language_",
          children: "document"
        }), ".", jsx(_components.span, {
          className: "hljs-title function_",
          children: "createElement"
        }), "(", jsx(_components.span, {
          className: "hljs-string",
          children: "\"div\""
        }), ");\n\nclickTest.", jsx(_components.span, {
          className: "hljs-title function_",
          children: "before"
        }), "(", jsx(_components.span, {
          className: "hljs-function",
          children: "() =>"
        }), " {\n  ", jsx(_components.span, {
          className: "hljs-variable language_",
          children: "document"
        }), ".", jsx(_components.span, {
          className: "hljs-property",
          children: "body"
        }), ".", jsx(_components.span, {
          className: "hljs-title function_",
          children: "appendChild"
        }), "(ref);\n});\n\nclickTest.", jsx(_components.span, {
          className: "hljs-title function_",
          children: "after"
        }), "(", jsx(_components.span, {
          className: "hljs-function",
          children: "() =>"
        }), " {\n  ", jsx(_components.span, {
          className: "hljs-variable language_",
          children: "document"
        }), ".", jsx(_components.span, {
          className: "hljs-property",
          children: "body"
        }), ".", jsx(_components.span, {
          className: "hljs-title function_",
          children: "removeChild"
        }), "(ref);\n});\n\n", jsx(_components.span, {
          className: "hljs-title function_",
          children: "clickTest"
        }), "(", jsx(_components.span, {
          className: "hljs-string",
          children: "'外側のクリックでトリガーされる'"
        }), ", ", jsx(_components.span, {
          className: "hljs-function",
          children: "() =>"
        }), "\n  ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "createRoot"
        }), "(\n    ", jsxs(_components.span, {
          className: "hljs-function",
          children: ["(", jsx(_components.span, {
            className: "hljs-params",
            children: "dispose"
          }), ") =>"]
        }), "\n      ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "new"
        }), " ", jsx(_components.span, {
          className: "hljs-title class_",
          children: "Promise"
        }), "<", jsx(_components.span, {
          className: "hljs-built_in",
          children: "void"
        }), ">(", jsxs(_components.span, {
          className: "hljs-function",
          children: ["(", jsx(_components.span, {
            className: "hljs-params",
            children: "resolve"
          }), ") =>"]
        }), " {\n        ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "let"
        }), " clickedOutside = ", jsx(_components.span, {
          className: "hljs-literal",
          children: "false"
        }), ";\n        ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "clickOutside"
        }), "(ref, ", jsx(_components.span, {
          className: "hljs-function",
          children: "() =>"
        }), " ", jsx(_components.span, {
          className: "hljs-function",
          children: "() =>"
        }), " {\n          clickedOutside = ", jsx(_components.span, {
          className: "hljs-literal",
          children: "true"
        }), ";\n        });\n        ", jsx(_components.span, {
          className: "hljs-variable language_",
          children: "document"
        }), ".", jsx(_components.span, {
          className: "hljs-property",
          children: "body"
        }), ".", jsx(_components.span, {
          className: "hljs-title function_",
          children: "addEventListener"
        }), "(", jsx(_components.span, {
          className: "hljs-string",
          children: "\"click\""
        }), ", ", jsx(_components.span, {
          className: "hljs-function",
          children: "() =>"
        }), " {\n          assert.", jsx(_components.span, {
          className: "hljs-title function_",
          children: "ok"
        }), "(clickedOutside);\n          ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "dispose"
        }), "();\n          ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "resolve"
        }), "();\n        });\n        fireEvent.", jsx(_components.span, {
          className: "hljs-title function_",
          children: "click"
        }), "(", jsx(_components.span, {
          className: "hljs-variable language_",
          children: "document"
        }), ".", jsx(_components.span, {
          className: "hljs-property",
          children: "body"
        }), ");\n      })\n  )\n);\n\n", jsx(_components.span, {
          className: "hljs-title function_",
          children: "clickTest"
        }), "(", jsx(_components.span, {
          className: "hljs-string",
          children: "'内側のクリックではトリガーされない'"
        }), ", ", jsx(_components.span, {
          className: "hljs-function",
          children: "() =>"
        }), "\n  ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "createRoot"
        }), "(\n    ", jsxs(_components.span, {
          className: "hljs-function",
          children: ["(", jsx(_components.span, {
            className: "hljs-params",
            children: "dispose"
          }), ") =>"]
        }), "\n      ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "new"
        }), " ", jsx(_components.span, {
          className: "hljs-title class_",
          children: "Promise"
        }), "<", jsx(_components.span, {
          className: "hljs-built_in",
          children: "void"
        }), ">(", jsxs(_components.span, {
          className: "hljs-function",
          children: ["(", jsx(_components.span, {
            className: "hljs-params",
            children: "resolve"
          }), ") =>"]
        }), " {\n        ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "let"
        }), " clickedOutside = ", jsx(_components.span, {
          className: "hljs-literal",
          children: "false"
        }), ";\n        ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "clickOutside"
        }), "(ref, ", jsx(_components.span, {
          className: "hljs-function",
          children: "() =>"
        }), " ", jsx(_components.span, {
          className: "hljs-function",
          children: "() =>"
        }), " {\n          clickedOutside = ", jsx(_components.span, {
          className: "hljs-literal",
          children: "true"
        }), ";\n        });\n        ref.", jsx(_components.span, {
          className: "hljs-title function_",
          children: "addEventListener"
        }), "(", jsx(_components.span, {
          className: "hljs-string",
          children: "\"click\""
        }), ", ", jsx(_components.span, {
          className: "hljs-function",
          children: "() =>"
        }), " {\n          assert.", jsx(_components.span, {
          className: "hljs-title function_",
          children: "is"
        }), "(clickedOutside, ", jsx(_components.span, {
          className: "hljs-literal",
          children: "false"
        }), ");\n          ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "dispose"
        }), "();\n          ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "resolve"
        }), "();\n        });\n        fireEvent.", jsx(_components.span, {
          className: "hljs-title function_",
          children: "click"
        }), "(ref);\n      })\n  )\n);\n\nclickTest.", jsx(_components.span, {
          className: "hljs-title function_",
          children: "run"
        }), "();\n"]
      })
    }), "\n", jsxs(_components.h3, {
      id: "コンポーネントのテスト",
      children: [jsx(_components.a, {
        className: "header-anchor",
        href: "#コンポーネントのテスト",
        children: "#"
      }), "コンポーネントのテスト"]
    }), "\n", jsx(_components.p, {
      children: "テストするための、シンプルなクリックカウンターコンポーネントを見てみましょう:"
    }), "\n", jsx(_components.pre, {
      children: jsxs(_components.code, {
        className: "hljs language-ts",
        children: [jsx(_components.span, {
          className: "hljs-comment",
          children: "// main.tsx"
        }), "\n", jsx(_components.span, {
          className: "hljs-keyword",
          children: "import"
        }), " { createSignal, ", jsx(_components.span, {
          className: "hljs-title class_",
          children: "Component"
        }), " } ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "from"
        }), " ", jsx(_components.span, {
          className: "hljs-string",
          children: "\"solid-js\""
        }), ";\n\n", jsx(_components.span, {
          className: "hljs-keyword",
          children: "export"
        }), " ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "const"
        }), " ", jsx(_components.span, {
          className: "hljs-title class_",
          children: "Counter"
        }), ": ", jsx(_components.span, {
          className: "hljs-title class_",
          children: "Component"
        }), " = ", jsx(_components.span, {
          className: "hljs-function",
          children: "() =>"
        }), " {\n  ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "const"
        }), " [count, setCount] = ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "createSignal"
        }), "(", jsx(_components.span, {
          className: "hljs-number",
          children: "0"
        }), ");\n\n  ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "return"
        }), " (\n    ", jsxs(_components.span, {
          className: "xml",
          children: [jsxs(_components.span, {
            className: "hljs-tag",
            children: ["<", jsx(_components.span, {
              className: "hljs-name",
              children: "div"
            }), " ", jsx(_components.span, {
              className: "hljs-attr",
              children: "role"
            }), "=", jsx(_components.span, {
              className: "hljs-string",
              children: "\"button\""
            }), " ", jsx(_components.span, {
              className: "hljs-attr",
              children: "onClick"
            }), "=", jsx(_components.span, {
              className: "hljs-string",
              children: "{()"
            }), " =>"]
          }), " setCount((c) => c + 1)}>\n      Count: {count()}\n    ", jsxs(_components.span, {
            className: "hljs-tag",
            children: ["</", jsx(_components.span, {
              className: "hljs-name",
              children: "div"
            }), ">"]
          })]
        }), "\n  );\n};\n"]
      })
    }), "\n", jsxs(_components.p, {
      children: ["ここでは、", jsx(_components.code, {
        children: "solid-testing-library"
      }), " を使用します。最も重要なヘルパーは、何とかして DOM にコンポーネントをレンダリングする ", jsx(_components.code, {
        children: "render"
      }), " と、実際のユーザーイベントに似た方法でイベントをディスパッチする ", jsx(_components.code, {
        children: "fireEvent"
      }), " と、グローバルセレクターを提供する ", jsx(_components.code, {
        children: "screen"
      }), " です。また、", jsx(_components.code, {
        children: "@testing-library/jest-dom"
      }), " が提供する ", jsx(_components.code, {
        children: "expect"
      }), " に追加された有用なアサーションも利用しています。"]
    }), "\n", jsxs(_components.h4, {
      id: "jest-でのテスト-2",
      children: [jsx(_components.a, {
        className: "header-anchor",
        href: "#jest-でのテスト-2",
        children: "#"
      }), "Jest でのテスト"]
    }), "\n", jsx(_components.pre, {
      children: jsxs(_components.code, {
        className: "hljs language-ts",
        children: [jsx(_components.span, {
          className: "hljs-comment",
          children: "// main.test.tsx"
        }), "\n", jsx(_components.span, {
          className: "hljs-keyword",
          children: "import"
        }), " { ", jsx(_components.span, {
          className: "hljs-title class_",
          children: "Counter"
        }), " } ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "from"
        }), " ", jsx(_components.span, {
          className: "hljs-string",
          children: "\"./main\""
        }), ";\n", jsx(_components.span, {
          className: "hljs-keyword",
          children: "import"
        }), " { cleanup, fireEvent, render, screen } ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "from"
        }), " ", jsx(_components.span, {
          className: "hljs-string",
          children: "\"solid-testing-library\""
        }), ";\n\n", jsx(_components.span, {
          className: "hljs-title function_",
          children: "describe"
        }), "(", jsx(_components.span, {
          className: "hljs-string",
          children: "\"Counter\""
        }), ", ", jsx(_components.span, {
          className: "hljs-function",
          children: "() =>"
        }), " {\n  ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "afterEach"
        }), "(cleanup);\n\n  ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "test"
        }), "(", jsx(_components.span, {
          className: "hljs-string",
          children: "\"ゼロから始まる\""
        }), ", ", jsx(_components.span, {
          className: "hljs-function",
          children: "() =>"
        }), " {\n    ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "render"
        }), "(", jsx(_components.span, {
          className: "hljs-function",
          children: "() =>"
        }), " ", jsx(_components.span, {
          className: "xml",
          children: jsxs(_components.span, {
            className: "hljs-tag",
            children: ["<", jsx(_components.span, {
              className: "hljs-name",
              children: "Counter"
            }), " />"]
          })
        }), ");\n    ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "const"
        }), " button = screen.", jsx(_components.span, {
          className: "hljs-title function_",
          children: "getByRole"
        }), "(", jsx(_components.span, {
          className: "hljs-string",
          children: "\"button\""
        }), ");\n    ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "expect"
        }), "(button).", jsx(_components.span, {
          className: "hljs-title function_",
          children: "toBeInTheDocument"
        }), "();\n    ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "expect"
        }), "(button).", jsx(_components.span, {
          className: "hljs-title function_",
          children: "toHaveTextContent"
        }), "(", jsx(_components.span, {
          className: "hljs-string",
          children: "\"Count: 0\""
        }), ");\n  });\n\n  ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "test"
        }), "(", jsx(_components.span, {
          className: "hljs-string",
          children: "\"クリックで値が 1 増える\""
        }), ", ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "async"
        }), " () => {\n    ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "render"
        }), "(", jsx(_components.span, {
          className: "hljs-function",
          children: "() =>"
        }), " ", jsx(_components.span, {
          className: "xml",
          children: jsxs(_components.span, {
            className: "hljs-tag",
            children: ["<", jsx(_components.span, {
              className: "hljs-name",
              children: "Counter"
            }), " />"]
          })
        }), ");\n    ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "const"
        }), " button = screen.", jsx(_components.span, {
          className: "hljs-title function_",
          children: "getByRole"
        }), "(", jsx(_components.span, {
          className: "hljs-string",
          children: "\"button\""
        }), ");\n    fireEvent.", jsx(_components.span, {
          className: "hljs-title function_",
          children: "click"
        }), "(button);\n    ", jsx(_components.span, {
          className: "hljs-comment",
          children: "// イベントループが終了するのにひとつのプロミスを解決する必要があります"
        }), "\n    ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "await"
        }), " ", jsx(_components.span, {
          className: "hljs-title class_",
          children: "Promise"
        }), ".", jsx(_components.span, {
          className: "hljs-title function_",
          children: "resolve"
        }), "();\n    ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "expect"
        }), "(button).", jsx(_components.span, {
          className: "hljs-title function_",
          children: "toHaveTextContent"
        }), "(", jsx(_components.span, {
          className: "hljs-string",
          children: "\"Count: 1\""
        }), ");\n    fireEvent.", jsx(_components.span, {
          className: "hljs-title function_",
          children: "click"
        }), "(button);\n    ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "await"
        }), " ", jsx(_components.span, {
          className: "hljs-title class_",
          children: "Promise"
        }), ".", jsx(_components.span, {
          className: "hljs-title function_",
          children: "resolve"
        }), "();\n    ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "expect"
        }), "(button).", jsx(_components.span, {
          className: "hljs-title function_",
          children: "toHaveTextContent"
        }), "(", jsx(_components.span, {
          className: "hljs-string",
          children: "\"Count: 2\""
        }), ");\n  });\n});\n"]
      })
    }), "\n", jsxs(_components.h4, {
      id: "uvu-でのテスト-2",
      children: [jsx(_components.a, {
        className: "header-anchor",
        href: "#uvu-でのテスト-2",
        children: "#"
      }), "uvu でのテスト"]
    }), "\n", jsx(_components.pre, {
      children: jsxs(_components.code, {
        className: "hljs language-ts",
        children: [jsx(_components.span, {
          className: "hljs-comment",
          children: "// main.test.tsx"
        }), "\n", jsx(_components.span, {
          className: "hljs-keyword",
          children: "import"
        }), " { suite } ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "from"
        }), " ", jsx(_components.span, {
          className: "hljs-string",
          children: "\"uvu\""
        }), ";\n", jsx(_components.span, {
          className: "hljs-keyword",
          children: "import"
        }), " * ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "as"
        }), " assert ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "from"
        }), " ", jsx(_components.span, {
          className: "hljs-string",
          children: "\"uvu/assert\""
        }), ";\n", jsx(_components.span, {
          className: "hljs-keyword",
          children: "import"
        }), " { ", jsx(_components.span, {
          className: "hljs-title class_",
          children: "Counter"
        }), " } ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "from"
        }), " ", jsx(_components.span, {
          className: "hljs-string",
          children: "\"main\""
        }), ";\n", jsx(_components.span, {
          className: "hljs-keyword",
          children: "import"
        }), " { fireEvent, render, screen } ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "from"
        }), " ", jsx(_components.span, {
          className: "hljs-string",
          children: "\"solid-testing-library\""
        }), ";\n", jsx(_components.span, {
          className: "hljs-keyword",
          children: "import"
        }), " { isInDocument, hasTextContent } ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "from"
        }), " ", jsx(_components.span, {
          className: "hljs-string",
          children: "\"solid-dom-testing\""
        }), ";\n\n", jsx(_components.span, {
          className: "hljs-keyword",
          children: "const"
        }), " testCounter = ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "suite"
        }), "(", jsx(_components.span, {
          className: "hljs-string",
          children: "\"Counter\""
        }), ");\n\ntestCounter.", jsx(_components.span, {
          className: "hljs-property",
          children: "after"
        }), ".", jsx(_components.span, {
          className: "hljs-title function_",
          children: "each"
        }), "(cleanup);\n\n", jsx(_components.span, {
          className: "hljs-title function_",
          children: "testCounter"
        }), "(", jsx(_components.span, {
          className: "hljs-string",
          children: "\"ゼロから始まる\""
        }), ", ", jsx(_components.span, {
          className: "hljs-function",
          children: "() =>"
        }), " {\n  ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "const"
        }), " { getByRole } = ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "render"
        }), "(", jsx(_components.span, {
          className: "hljs-function",
          children: "() =>"
        }), " ", jsx(_components.span, {
          className: "xml",
          children: jsxs(_components.span, {
            className: "hljs-tag",
            children: ["<", jsx(_components.span, {
              className: "hljs-name",
              children: "Counter"
            }), " />"]
          })
        }), ");\n  ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "const"
        }), " button = ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "getByRole"
        }), "(", jsx(_components.span, {
          className: "hljs-string",
          children: "\"button\""
        }), ");\n  assert.", jsx(_components.span, {
          className: "hljs-title function_",
          children: "ok"
        }), "(", jsx(_components.span, {
          className: "hljs-title function_",
          children: "isInDocument"
        }), "(button), ", jsx(_components.span, {
          className: "hljs-string",
          children: "\"button not in dom\""
        }), ");\n  assert.", jsx(_components.span, {
          className: "hljs-title function_",
          children: "ok"
        }), "(", jsx(_components.span, {
          className: "hljs-title function_",
          children: "hasTextContent"
        }), "(button, ", jsx(_components.span, {
          className: "hljs-string",
          children: "\"Count: 0\""
        }), "), ", jsx(_components.span, {
          className: "hljs-string",
          children: "\"wrong text content\""
        }), ");\n});\n\n", jsx(_components.span, {
          className: "hljs-title function_",
          children: "testCounter"
        }), "(", jsx(_components.span, {
          className: "hljs-string",
          children: "\"クリックで値が 1 増える\""
        }), ", ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "async"
        }), " () => {\n  ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "render"
        }), "(", jsx(_components.span, {
          className: "hljs-function",
          children: "() =>"
        }), " ", jsx(_components.span, {
          className: "xml",
          children: jsxs(_components.span, {
            className: "hljs-tag",
            children: ["<", jsx(_components.span, {
              className: "hljs-name",
              children: "Counter"
            }), " />"]
          })
        }), ");\n  ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "const"
        }), " button = screen.", jsx(_components.span, {
          className: "hljs-title function_",
          children: "getByRole"
        }), "(", jsx(_components.span, {
          className: "hljs-string",
          children: "\"button\""
        }), ");\n  fireEvent.", jsx(_components.span, {
          className: "hljs-title function_",
          children: "click"
        }), "(button);\n  ", jsx(_components.span, {
          className: "hljs-comment",
          children: "// イベントループが終了するのにひとつのプロミスを解決する必要があります"
        }), "\n  ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "await"
        }), " ", jsx(_components.span, {
          className: "hljs-title class_",
          children: "Promise"
        }), ".", jsx(_components.span, {
          className: "hljs-title function_",
          children: "resolve"
        }), "();\n  assert.", jsx(_components.span, {
          className: "hljs-title function_",
          children: "ok"
        }), "(\n    ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "hasTextContent"
        }), "(button, ", jsx(_components.span, {
          className: "hljs-string",
          children: "\"Count: 1\""
        }), "),\n    ", jsx(_components.span, {
          className: "hljs-string",
          children: "\"not count 1 after first click\""
        }), "\n  );\n  fireEvent.", jsx(_components.span, {
          className: "hljs-title function_",
          children: "click"
        }), "(button);\n  ", jsx(_components.span, {
          className: "hljs-keyword",
          children: "await"
        }), " ", jsx(_components.span, {
          className: "hljs-title class_",
          children: "Promise"
        }), ".", jsx(_components.span, {
          className: "hljs-title function_",
          children: "resolve"
        }), "();\n  assert.", jsx(_components.span, {
          className: "hljs-title function_",
          children: "ok"
        }), "(\n    ", jsx(_components.span, {
          className: "hljs-title function_",
          children: "hasTextContent"
        }), "(button, ", jsx(_components.span, {
          className: "hljs-string",
          children: "\"Count: 2\""
        }), "),\n    ", jsx(_components.span, {
          className: "hljs-string",
          children: "\"not count 2 after first click\""
        }), "\n  );\n});\n\ntestCounter.", jsx(_components.span, {
          className: "hljs-title function_",
          children: "run"
        }), "();\n"]
      })
    })]
  });
}
function MDXContent(props = {}) {
  const {wrapper: MDXLayout} = props.components || ({});
  return MDXLayout ? jsx(MDXLayout, Object.assign({}, props, {
    children: jsx(_createMdxContent, props)
  })) : _createMdxContent(props);
}

export { MDXContent as default, toc };
//# sourceMappingURL=testing-3a49f55d.js.map
