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 Mode",
        "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: "我们为两个测试运行器提供支持："
    }), "\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 集成基于 ", jsx(_components.a, {
        href: "https://github.com/solidjs/solid-jest",
        children: "solid-jest/preset/browser"
      }), " Jest 配置预设，它允许您在浏览器中使用 Solid。这使用 babel 来转换 Solid 代码。"]
    }), "\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: "# or pnpm install or 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"
      }), " 以帮助您编写对测试库有用的断言。"]
    }), "\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: "# or pnpm install or 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: "# or yarn add -D or 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 -r html"
      }), " 而不是 ", jsx(_components.code, {
        children: "c8"
      }), " 来启用 html 报告器。"]
    }), "\n", jsxs(_components.h4, {
      id: "watch-mode",
      children: [jsx(_components.a, {
        className: "header-anchor",
        href: "#watch-mode",
        children: "#"
      }), "Watch Mode"]
    }), "\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: "# or yarn add -D or 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: "reactive root"
      }), " 之外，您的状态不会被跟踪，更新不会触发 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: "\"it reads pre-existing state from 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: "\"it stores new state to 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: "// to catch an effect, use an 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: "\"it updates state multiple times\""
        }), ", ", 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: "// wait a tick to resolve all effects"
        }), "\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: "\"it reads pre-existing state from 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: "\"it stores new state to 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: "// to catch an effect, we need an 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: "指令"
      }), " 允许以可重用的方式使用 refs。它们基本上是遵循 ", 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: "\"will trigger on click outside\""
        }), ", ", 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: "\"will not trigger on click inside\""
        }), ", ", 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: "\"will trigger on click outside\""
        }), ", ", 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: "\"will not trigger on click inside\""
        }), ", ", 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"
      }), "。最重要的助手是 ", jsx(_components.code, {
        children: "render"
      }), " 以托管方式将组件渲染到 DOM，", 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: "\"it starts with zero\""
        }), ", ", 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: "\"it increases its value on click\""
        }), ", ", 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: "// the event loop takes one Promise to resolve to be finished"
        }), "\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: "\"it starts with zero\""
        }), ", ", 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: "\"it increases its value on click\""
        }), ", ", 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: "// the event loop takes one Promise to resolve to be finished"
        }), "\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-a15bdcea.js.map
