diff --git a/.gitignore b/.gitignore
index 5c447595b..0a9a8aabe 100755
--- a/.gitignore
+++ b/.gitignore
@@ -8,7 +8,6 @@ lib/core/MetadataBlog.js
translated_docs
build/
-i18n/*
.docusaurus
.cache-loader
diff --git a/docusaurus.config.js b/docusaurus.config.js
index 8357abc06..6500bde83 100644
--- a/docusaurus.config.js
+++ b/docusaurus.config.js
@@ -215,6 +215,7 @@ module.exports = {
remarkPlugins: [
[require('@docusaurus/remark-plugin-npm2yarn'), { sync: true }],
],
+ editLocalizedFiles: true,
editUrl:
'https://github.com/testing-library/testing-library-docs/edit/main/',
path: './docs',
@@ -263,6 +264,10 @@ module.exports = {
label: 'Examples',
position: 'left',
},
+ {
+ type: 'localeDropdown',
+ position: 'right',
+ },
{
to: '/help',
label: 'Help',
@@ -356,4 +361,8 @@ module.exports = {
indexName: 'testing-library',
},
},
+ i18n: {
+ defaultLocale: 'en',
+ locales: ['en', 'zh-Hans']
+ }
}
diff --git a/i18n/zh-Hans/code.json b/i18n/zh-Hans/code.json
new file mode 100644
index 000000000..db1cc8777
--- /dev/null
+++ b/i18n/zh-Hans/code.json
@@ -0,0 +1,471 @@
+{
+ "theme.ErrorPageContent.title": {
+ "message": "页面已崩溃。",
+ "description": "The title of the fallback page when the page crashed"
+ },
+ "theme.ErrorPageContent.tryAgain": {
+ "message": "重试",
+ "description": "The label of the button to try again when the page crashed"
+ },
+ "theme.NotFound.title": {
+ "message": "找不到页面",
+ "description": "The title of the 404 page"
+ },
+ "theme.NotFound.p1": {
+ "message": "我们找不到您要找的页面。",
+ "description": "The first paragraph of the 404 page"
+ },
+ "theme.NotFound.p2": {
+ "message": "请联系原始链接来源网站的所有者,并告知他们链接已损坏。",
+ "description": "The 2nd paragraph of the 404 page"
+ },
+ "theme.AnnouncementBar.closeButtonAriaLabel": {
+ "message": "关闭",
+ "description": "The ARIA label for close button of announcement bar"
+ },
+ "theme.admonition.note": {
+ "message": "备注",
+ "description": "The default label used for the Note admonition (:::note)"
+ },
+ "theme.admonition.tip": {
+ "message": "提示",
+ "description": "The default label used for the Tip admonition (:::tip)"
+ },
+ "theme.admonition.danger": {
+ "message": "危险",
+ "description": "The default label used for the Danger admonition (:::danger)"
+ },
+ "theme.admonition.info": {
+ "message": "信息",
+ "description": "The default label used for the Info admonition (:::info)"
+ },
+ "theme.admonition.caution": {
+ "message": "警告",
+ "description": "The default label used for the Caution admonition (:::caution)"
+ },
+ "theme.BackToTopButton.buttonAriaLabel": {
+ "message": "回到顶部",
+ "description": "The ARIA label for the back to top button"
+ },
+ "theme.blog.archive.title": {
+ "message": "历史博文",
+ "description": "The page & hero title of the blog archive page"
+ },
+ "theme.blog.archive.description": {
+ "message": "历史博文",
+ "description": "The page & hero description of the blog archive page"
+ },
+ "theme.blog.paginator.navAriaLabel": {
+ "message": "博文列表分页导航",
+ "description": "The ARIA label for the blog pagination"
+ },
+ "theme.blog.paginator.newerEntries": {
+ "message": "较新的博文",
+ "description": "The label used to navigate to the newer blog posts page (previous page)"
+ },
+ "theme.blog.paginator.olderEntries": {
+ "message": "较旧的博文",
+ "description": "The label used to navigate to the older blog posts page (next page)"
+ },
+ "theme.blog.post.paginator.navAriaLabel": {
+ "message": "博文分页导航",
+ "description": "The ARIA label for the blog posts pagination"
+ },
+ "theme.blog.post.paginator.newerPost": {
+ "message": "较新一篇",
+ "description": "The blog post button label to navigate to the newer/previous post"
+ },
+ "theme.blog.post.paginator.olderPost": {
+ "message": "较旧一篇",
+ "description": "The blog post button label to navigate to the older/next post"
+ },
+ "theme.blog.post.plurals": {
+ "message": "{count} 篇博文",
+ "description": "Pluralized label for \"{count} posts\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)"
+ },
+ "theme.blog.tagTitle": {
+ "message": "{nPosts} 含有标签「{tagName}」",
+ "description": "The title of the page for a blog tag"
+ },
+ "theme.tags.tagsPageLink": {
+ "message": "查看所有标签",
+ "description": "The label of the link targeting the tag list page"
+ },
+ "theme.colorToggle.ariaLabel": {
+ "message": "切换浅色/暗黑模式(当前为{mode})",
+ "description": "The ARIA label for the navbar color mode toggle"
+ },
+ "theme.colorToggle.ariaLabel.mode.dark": {
+ "message": "暗黑模式",
+ "description": "The name for the dark color mode"
+ },
+ "theme.colorToggle.ariaLabel.mode.light": {
+ "message": "浅色模式",
+ "description": "The name for the light color mode"
+ },
+ "theme.docs.breadcrumbs.home": {
+ "message": "主页面",
+ "description": "The ARIA label for the home page in the breadcrumbs"
+ },
+ "theme.docs.breadcrumbs.navAriaLabel": {
+ "message": "页面路径",
+ "description": "The ARIA label for the breadcrumbs"
+ },
+ "theme.docs.DocCard.categoryDescription": {
+ "message": "{count} 个项目",
+ "description": "The default description for a category card in the generated index about how many items this category includes"
+ },
+ "theme.docs.paginator.navAriaLabel": {
+ "message": "文档分页导航",
+ "description": "The ARIA label for the docs pagination"
+ },
+ "theme.docs.paginator.previous": {
+ "message": "上一页",
+ "description": "The label used to navigate to the previous doc"
+ },
+ "theme.docs.paginator.next": {
+ "message": "下一页",
+ "description": "The label used to navigate to the next doc"
+ },
+ "theme.docs.tagDocListPageTitle.nDocsTagged": {
+ "message": "{count} 篇文档带有标签",
+ "description": "Pluralized label for \"{count} docs tagged\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)"
+ },
+ "theme.docs.tagDocListPageTitle": {
+ "message": "{nDocsTagged}「{tagName}」",
+ "description": "The title of the page for a docs tag"
+ },
+ "theme.docs.versionBadge.label": {
+ "message": "版本:{versionLabel}"
+ },
+ "theme.common.editThisPage": {
+ "message": "编辑此页",
+ "description": "The link label to edit the current page"
+ },
+ "theme.docs.versions.unreleasedVersionLabel": {
+ "message": "此为 {siteTitle} {versionLabel} 版尚未发行的文档。",
+ "description": "The label used to tell the user that he's browsing an unreleased doc version"
+ },
+ "theme.docs.versions.unmaintainedVersionLabel": {
+ "message": "此为 {siteTitle} {versionLabel} 版的文档,现已不再积极维护。",
+ "description": "The label used to tell the user that he's browsing an unmaintained doc version"
+ },
+ "theme.docs.versions.latestVersionSuggestionLabel": {
+ "message": "最新的文档请参阅 {latestVersionLink} ({versionLabel})。",
+ "description": "The label used to tell the user to check the latest version"
+ },
+ "theme.docs.versions.latestVersionLinkLabel": {
+ "message": "最新版本",
+ "description": "The label used for the latest version suggestion link label"
+ },
+ "theme.common.headingLinkTitle": {
+ "message": "标题的直接链接",
+ "description": "Title for link to heading"
+ },
+ "theme.lastUpdated.atDate": {
+ "message": "于 {date} ",
+ "description": "The words used to describe on which date a page has been last updated"
+ },
+ "theme.lastUpdated.byUser": {
+ "message": "由 {user} ",
+ "description": "The words used to describe by who the page has been last updated"
+ },
+ "theme.lastUpdated.lastUpdatedAtBy": {
+ "message": "最后{byUser}{atDate}更新",
+ "description": "The sentence used to display when a page has been last updated, and by who"
+ },
+ "theme.navbar.mobileVersionsDropdown.label": {
+ "message": "选择版本",
+ "description": "The label for the navbar versions dropdown on mobile view"
+ },
+ "theme.common.skipToMainContent": {
+ "message": "跳到主要内容",
+ "description": "The skip to content label used for accessibility, allowing to rapidly navigate to main content with keyboard tab/enter navigation"
+ },
+ "theme.tags.tagsListLabel": {
+ "message": "标签:",
+ "description": "The label alongside a tag list"
+ },
+ "theme.blog.sidebar.navAriaLabel": {
+ "message": "最近博文导航",
+ "description": "The ARIA label for recent posts in the blog sidebar"
+ },
+ "theme.CodeBlock.copied": {
+ "message": "复制成功",
+ "description": "The copied button label on code blocks"
+ },
+ "theme.CodeBlock.copyButtonAriaLabel": {
+ "message": "复制代码到剪贴板",
+ "description": "The ARIA label for copy code blocks button"
+ },
+ "theme.CodeBlock.copy": {
+ "message": "复制",
+ "description": "The copy button label on code blocks"
+ },
+ "theme.CodeBlock.wordWrapToggle": {
+ "message": "切换自动换行",
+ "description": "The title attribute for toggle word wrapping button of code block lines"
+ },
+ "theme.DocSidebarItem.toggleCollapsedCategoryAriaLabel": {
+ "message": "打开/收起侧边栏菜单「{label}」",
+ "description": "The ARIA label to toggle the collapsible sidebar category"
+ },
+ "theme.navbar.mobileLanguageDropdown.label": {
+ "message": "选择语言",
+ "description": "The label for the mobile language switcher dropdown"
+ },
+ "theme.TOCCollapsible.toggleButtonLabel": {
+ "message": "本页总览",
+ "description": "The label used by the button on the collapsible TOC component"
+ },
+ "theme.blog.post.readMore": {
+ "message": "阅读更多",
+ "description": "The label used in blog post item excerpts to link to full blog posts"
+ },
+ "theme.blog.post.readMoreLabel": {
+ "message": "阅读 {title} 的全文",
+ "description": "The ARIA label for the link to full blog posts from excerpts"
+ },
+ "theme.blog.post.readingTime.plurals": {
+ "message": "阅读需 {readingTime} 分钟",
+ "description": "Pluralized label for \"{readingTime} min read\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)"
+ },
+ "theme.docs.sidebar.collapseButtonTitle": {
+ "message": "收起侧边栏",
+ "description": "The title attribute for collapse button of doc sidebar"
+ },
+ "theme.docs.sidebar.collapseButtonAriaLabel": {
+ "message": "收起侧边栏",
+ "description": "The title attribute for collapse button of doc sidebar"
+ },
+ "theme.docs.sidebar.expandButtonTitle": {
+ "message": "展开侧边栏",
+ "description": "The ARIA label and title attribute for expand button of doc sidebar"
+ },
+ "theme.docs.sidebar.expandButtonAriaLabel": {
+ "message": "展开侧边栏",
+ "description": "The ARIA label and title attribute for expand button of doc sidebar"
+ },
+ "theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": {
+ "message": "← 回到主菜单",
+ "description": "The label of the back button to return to main menu, inside the mobile navbar sidebar secondary menu (notably used to display the docs sidebar)"
+ },
+ "theme.SearchPage.documentsFound.plurals": {
+ "message": "找到 {count} 份文件",
+ "description": "Pluralized label for \"{count} documents found\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)"
+ },
+ "theme.SearchPage.existingResultsTitle": {
+ "message": "「{query}」的搜索结果",
+ "description": "The search page title for non-empty query"
+ },
+ "theme.SearchPage.emptyResultsTitle": {
+ "message": "在文档中搜索",
+ "description": "The search page title for empty query"
+ },
+ "theme.SearchPage.inputPlaceholder": {
+ "message": "在此输入搜索字词",
+ "description": "The placeholder for search page input"
+ },
+ "theme.SearchPage.inputLabel": {
+ "message": "搜索",
+ "description": "The ARIA label for search page input"
+ },
+ "theme.SearchPage.algoliaLabel": {
+ "message": "通过 Algolia 搜索",
+ "description": "The ARIA label for Algolia mention"
+ },
+ "theme.SearchPage.noResultsText": {
+ "message": "未找到任何结果",
+ "description": "The paragraph for empty search result"
+ },
+ "theme.SearchPage.fetchingNewResults": {
+ "message": "正在获取新的搜索结果...",
+ "description": "The paragraph for fetching new search results"
+ },
+ "theme.SearchBar.seeAll": {
+ "message": "查看全部 {count} 个结果"
+ },
+ "theme.SearchBar.label": {
+ "message": "搜索",
+ "description": "The ARIA label and placeholder for search button"
+ },
+ "theme.SearchModal.searchBox.resetButtonTitle": {
+ "message": "清除查询",
+ "description": "The label and ARIA label for search box reset button"
+ },
+ "theme.SearchModal.searchBox.cancelButtonText": {
+ "message": "取消",
+ "description": "The label and ARIA label for search box cancel button"
+ },
+ "theme.SearchModal.startScreen.recentSearchesTitle": {
+ "message": "最近搜索",
+ "description": "The title for recent searches"
+ },
+ "theme.SearchModal.startScreen.noRecentSearchesText": {
+ "message": "没有最近搜索",
+ "description": "The text when no recent searches"
+ },
+ "theme.SearchModal.startScreen.saveRecentSearchButtonTitle": {
+ "message": "保存这个搜索",
+ "description": "The label for save recent search button"
+ },
+ "theme.SearchModal.startScreen.removeRecentSearchButtonTitle": {
+ "message": "从历史记录中删除这个搜索",
+ "description": "The label for remove recent search button"
+ },
+ "theme.SearchModal.startScreen.favoriteSearchesTitle": {
+ "message": "收藏",
+ "description": "The title for favorite searches"
+ },
+ "theme.SearchModal.startScreen.removeFavoriteSearchButtonTitle": {
+ "message": "从收藏列表中删除这个搜索",
+ "description": "The label for remove favorite search button"
+ },
+ "theme.SearchModal.errorScreen.titleText": {
+ "message": "无法获取结果",
+ "description": "The title for error screen of search modal"
+ },
+ "theme.SearchModal.errorScreen.helpText": {
+ "message": "你可能需要检查网络连接。",
+ "description": "The help text for error screen of search modal"
+ },
+ "theme.SearchModal.footer.selectText": {
+ "message": "选中",
+ "description": "The explanatory text of the action for the enter key"
+ },
+ "theme.SearchModal.footer.selectKeyAriaLabel": {
+ "message": "Enter 键",
+ "description": "The ARIA label for the Enter key button that makes the selection"
+ },
+ "theme.SearchModal.footer.navigateText": {
+ "message": "导航",
+ "description": "The explanatory text of the action for the Arrow up and Arrow down key"
+ },
+ "theme.SearchModal.footer.navigateUpKeyAriaLabel": {
+ "message": "向上键",
+ "description": "The ARIA label for the Arrow up key button that makes the navigation"
+ },
+ "theme.SearchModal.footer.navigateDownKeyAriaLabel": {
+ "message": "向下键",
+ "description": "The ARIA label for the Arrow down key button that makes the navigation"
+ },
+ "theme.SearchModal.footer.closeText": {
+ "message": "关闭",
+ "description": "The explanatory text of the action for Escape key"
+ },
+ "theme.SearchModal.footer.closeKeyAriaLabel": {
+ "message": "Esc 键",
+ "description": "The ARIA label for the Escape key button that close the modal"
+ },
+ "theme.SearchModal.footer.searchByText": {
+ "message": "搜索提供",
+ "description": "The text explain that the search is making by Algolia"
+ },
+ "theme.SearchModal.noResultsScreen.noResultsText": {
+ "message": "没有结果:",
+ "description": "The text explains that there are no results for the following search"
+ },
+ "theme.SearchModal.noResultsScreen.suggestedQueryText": {
+ "message": "试试搜索",
+ "description": "The text for the suggested query when no results are found for the following search"
+ },
+ "theme.SearchModal.noResultsScreen.reportMissingResultsText": {
+ "message": "认为这个查询应该有结果?",
+ "description": "The text for the question where the user thinks there are missing results"
+ },
+ "theme.SearchModal.noResultsScreen.reportMissingResultsLinkText": {
+ "message": "请告知我们。",
+ "description": "The text for the link to report missing results"
+ },
+ "theme.SearchModal.placeholder": {
+ "message": "搜索文档",
+ "description": "The placeholder of the input of the DocSearch pop-up modal"
+ },
+ "pages.index.tagline": {
+ "message": "简单且完整的测试工具有助于鼓励好的测试实践"
+ },
+ "pages.index.Get Started": {
+ "message": "快速上手"
+ },
+ "pages.index.Write Maintainable Tests.title": {
+ "message": "编写可维护的测试"
+ },
+ "pages.index.Write Maintainable Tests.content": {
+ "message": "测试仅在你的应用程序中断时中断,而不是取决于实现细节"
+ },
+ "pages.index.Develop with Confidence.title": {
+ "message": "充满信心地开发"
+ },
+ "pages.index.Develop with Confidence.content": {
+ "message": "以与用户相同的方式与你的应用交互"
+ },
+ "pages.index.Accessible by Default.title": {
+ "message": "默认无障碍访问"
+ },
+ "pages.index.Accessible by Default.content": {
+ "message": "内置的选择器查找元素的方式和真正用户操作类似,写出更具包容性的测试代码"
+ },
+ "pages.index.The Problem": {
+ "message": "## 问题 \n - 你希望你的 UI 测试可以避免包含实现细节,并且专注于提升开发者的信心。 \n - 你希望你的测试代码是可维护的,因此重构 _(对实现的更改但不是功能的更改)_ 不会破坏你的测试并减慢团队的开发速度。"
+ },
+ "pages.index.The Solution": {
+ "message": "## 解决方案 \n Testing Library 系列包是一个轻量级的解决方案,无需所有的实现细节。它提供的元素查询功能和真正用户查找类似。通过这种方式,testing-library 有助于确保你的测试让你对 UI 代码充满信心。"
+ },
+ "pages.index.Guiding Principle": {
+ "message": "指导原则"
+ },
+ "pages.index.Guiding Principle.content": {
+ "message": "测试代码与你的软件使用方式越相似,它们能给你的信心就越大。"
+ },
+ "pages.index.Who is Using This": {
+ "message": "谁在使用?"
+ },
+ "pages.index.More Users": {
+ "message": "更多使用 {title} 的用户"
+ },
+ "pages.index.Awards": {
+ "message": "荣获奖项"
+ },
+ "pages.help.Need help": {
+ "message": "需要帮助?"
+ },
+ "pages.help.stackOverflow": {
+ "message": "在 [Stack Overflow](https://stackoverflow.com/questions/tagged/react-testing-library) 上提问"
+ },
+ "pages.help.spectrum": {
+ "message": "在 [Spectrum](https://spectrum.chat/testing-library) 上与社区成员讨论问题"
+ },
+ "pages.help.discord": {
+ "message": "在 [Discord](https://discord.gg/testing-library) 上讨论"
+ },
+ "pages.help.blog": {
+ "message": "关注 [博客]({baseUrl}blog),获取最新动态"
+ },
+ "pages.help.resources": {
+ "message": "浏览 [学习资料](/docs/learning)"
+ },
+ "pages.help.github": {
+ "message": "在 [GitHub]({repoUrl}) 上获得支持"
+ },
+ "pages.help.Buy a Course": {
+ "message": "购买在线课程"
+ },
+ "pages.help.Buy a Course.content": {
+ "message": "在 {testingjavascript} 上和 Testing Library 的作者 {kentcdodds} 一起学习如何测试 JavaScript。"
+ },
+ "pages.help.Want to help": {
+ "message": "想要提供帮助?"
+ },
+ "pages.help.Help maintain": {
+ "message": "谢谢!Testing Library 的维护者们很乐意与你以及社区一起维护这个库。我们不是在寻找资金资助,但我们需要每个人都能参与进来,使这个项目和社区取得成功,并从长远地改善每个人的测试能力。"
+ },
+ "pages.help.Help answer question": {
+ "message": "你可以通过上面的帮助链接帮助我们回答社区问题并更新文档内容。您还可以通过购买 {kentcdodds} 的 {courses} 或 {workshops} 来帮助支持他的财务。"
+ },
+ "pages.help.courses": {
+ "message": "在线课程"
+ },
+ "pages.help.remote workshops": {
+ "message": "远程工作坊"
+ }
+}
diff --git a/i18n/zh-Hans/docusaurus-plugin-content-blog/options.json b/i18n/zh-Hans/docusaurus-plugin-content-blog/options.json
new file mode 100644
index 000000000..9239ff706
--- /dev/null
+++ b/i18n/zh-Hans/docusaurus-plugin-content-blog/options.json
@@ -0,0 +1,14 @@
+{
+ "title": {
+ "message": "Blog",
+ "description": "The title for the blog used in SEO"
+ },
+ "description": {
+ "message": "Blog",
+ "description": "The description for the blog used in SEO"
+ },
+ "sidebar.title": {
+ "message": "Recent posts",
+ "description": "The label for the left sidebar"
+ }
+}
diff --git a/i18n/zh-Hans/docusaurus-plugin-content-docs/current.json b/i18n/zh-Hans/docusaurus-plugin-content-docs/current.json
new file mode 100644
index 000000000..deb56731b
--- /dev/null
+++ b/i18n/zh-Hans/docusaurus-plugin-content-docs/current.json
@@ -0,0 +1,82 @@
+{
+ "version.label": {
+ "message": "Next",
+ "description": "The label for version current"
+ },
+ "sidebar.recipes.category.Examples": {
+ "message": "示例",
+ "description": "The label for category Examples in sidebar recipes"
+ },
+ "sidebar.recipes.category.Help": {
+ "message": "帮助",
+ "description": "The label for category Help in sidebar recipes"
+ },
+ "sidebar.docs.category.Getting Started": {
+ "message": "快速上手",
+ "description": "The label for category Getting Started in sidebar docs"
+ },
+ "sidebar.docs.category.Core API": {
+ "message": "核心 API",
+ "description": "The label for category Core API in sidebar docs"
+ },
+ "sidebar.docs.category.Queries": {
+ "message": "查询",
+ "description": "The label for category Queries in sidebar docs"
+ },
+ "sidebar.docs.category.User Actions": {
+ "message": "用户动作",
+ "description": "The label for category User Actions in sidebar docs"
+ },
+ "sidebar.docs.category.Advanced": {
+ "message": "高级",
+ "description": "The label for category Advanced in sidebar docs"
+ },
+ "sidebar.docs.category.Frameworks": {
+ "message": "框架",
+ "description": "The label for category Frameworks in sidebar docs"
+ },
+ "sidebar.docs.category.DOM Testing Library": {
+ "message": "DOM Testing Library",
+ "description": "The label for category DOM Testing Library in sidebar docs"
+ },
+ "sidebar.docs.category.React Testing Library": {
+ "message": "React Testing Library",
+ "description": "The label for category React Testing Library in sidebar docs"
+ },
+ "sidebar.docs.category.Reason Testing Library": {
+ "message": "Reason Testing Library",
+ "description": "The label for category Reason Testing Library in sidebar docs"
+ },
+ "sidebar.docs.category.Native Testing Library": {
+ "message": "Native Testing Library",
+ "description": "The label for category Native Testing Library in sidebar docs"
+ },
+ "sidebar.docs.category.Vue Testing Library": {
+ "message": "Vue Testing Library",
+ "description": "The label for category Vue Testing Library in sidebar docs"
+ },
+ "sidebar.docs.category.Marko Testing Library": {
+ "message": "Marko Testing Library",
+ "description": "The label for category Marko Testing Library in sidebar docs"
+ },
+ "sidebar.docs.category.Angular Testing Library": {
+ "message": "Angular Testing Library",
+ "description": "The label for category Angular Testing Library in sidebar docs"
+ },
+ "sidebar.docs.category.Preact Testing Library": {
+ "message": "Preact Testing Library",
+ "description": "The label for category Preact Testing Library in sidebar docs"
+ },
+ "sidebar.docs.category.Svelte Testing Library": {
+ "message": "Svelte Testing Library",
+ "description": "The label for category Svelte Testing Library in sidebar docs"
+ },
+ "sidebar.docs.category.User Interactions": {
+ "message": "用户交互",
+ "description": "The label for category User Interactions in sidebar docs"
+ },
+ "sidebar.docs.category.Ecosystem": {
+ "message": "生态",
+ "description": "The label for category Ecosystem in sidebar docs"
+ }
+}
diff --git a/i18n/zh-Hans/docusaurus-plugin-content-docs/current/angular-testing-library/api.mdx b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/angular-testing-library/api.mdx
new file mode 100644
index 000000000..6f7ffcfd8
--- /dev/null
+++ b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/angular-testing-library/api.mdx
@@ -0,0 +1,455 @@
+---
+id: api
+title: API
+sidebar_label: API
+---
+
+`Angular Testing Library`重新导出了 `DOM Testing Library` 的所有内容以及 `render` 方法。
+
+以下的重新导出是经过 patch 的,使其更容易与Angular一起使用:
+
+- `fireEvent` 上的事件在事件被触发后自动调用一个变化检测周期
+- `findBy` 查询会在调用函数之前自动调用一个变化检测周期
+- `waitFor` 函数在调用回调函数之前自动调用一个变化检测周期
+
+## `render`
+
+通过Angular Testing Library,可以用两种方式渲染组件,通过组件的类型或用模板。
+
+> 默认情况下,`render` 也会导入 `NoopAnimationsModule`。
+
+## `Type`
+
+要渲染一个组件,你需要将组件的类型传递给 `render` 方法。对于不使用你的应用程序的其他部分的组件(例如设计模块或服务),
+渲染一个组件可以像下面的例子一样简单。
+
+```typescript
+await render(AppComponent)
+```
+
+## `template`
+
+你也可以提供一个模板,而不是把组件的类型作为第一个参数传递。这种做法是渲染指令所需要的,
+但也可以应用于组件,它甚至可能更有用。然后,指令的(或组件的)类型必须被添加到 `declarations` 中。
+
+**指令示例**:
+
+```typescript
+await render('
',
+})
+class ChildComponent {}
+
+@NgModule({
+ declarations: [ParentComponent, ChildComponent],
+})
+export class AppModule {}
+
+describe('ParentComponent', () => {
+ it('should not render ChildComponent when shallow rendering', async () => {
+ // all imports, declarations and exports of AppModule will be mocked.
+ const dependencies = MockBuilder(ParentComponent, AppModule).build();
+
+ await render(ParentComponent, dependencies)
+
+ expect(screen.queryByText('Child component')).toBeNull()
+ })
+})
+```
+
+
+
+
+
+
+ 我应该测试组件树的哪一层?子组件,父组件,还是两者?
+
+
+Following the guiding principle of this library, it is useful to break down how
+tests are organized around how the user experiences and interacts with
+application functionality rather than around specific components themselves. In
+some cases, for example for reusable component libraries, it might be useful to
+include developers in the list of users to test for and test each of the
+reusable components individually. Other times, the specific break down of a
+component tree is just an implementation detail and testing every component
+within that tree individually can cause issues (see
+https://kentcdodds.com/blog/avoid-the-test-user).
+
+In practice this means that it is often preferable to test high enough up the
+component tree to simulate realistic user interactions. The question of whether
+it is worth additionally testing at a higher or lower level on top of this comes
+down to a question of tradeoffs and what will provide enough value for the cost
+(see https://kentcdodds.com/blog/unit-vs-integration-vs-e2e-tests on more info
+on different levels of testing).
+
+For a more in-depth discussion of this topic see
+[this video](https://youtu.be/0qmPdcV-rN8).
+
+
+
+
+
+
+
+[guiding-principle]: https://twitter.com/kentcdodds/status/977018512689455106
+
+
diff --git a/i18n/zh-Hans/docusaurus-plugin-content-docs/current/angular-testing-library/intro.mdx b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/angular-testing-library/intro.mdx
new file mode 100644
index 000000000..a2c4fb050
--- /dev/null
+++ b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/angular-testing-library/intro.mdx
@@ -0,0 +1,45 @@
+---
+id: intro
+title: Angular Testing Library
+sidebar_label: 简介
+---
+
+[`Angular Testing Library`](https://github.com/testing-library/angular-testing-library)
+建立在
+[`DOM Testing Library`](https://github.com/testing-library/dom-testing-library)
+的基础上,增加了用于处理Angular组件的API。
+
+```bash npm2yarn
+npm install --save-dev @testing-library/angular
+```
+
+- [`@testing-library/angular-testing-library` on GitHub](https://github.com/testing-library/angular-testing-library)
+
+## 问题
+
+你想为你的 Angular 组件编写可维护的测试。作为这个目标的一部分,**你希望你的测试能避免包括组件的实现细节**。
+你应该把重点放在让你的测试给你带来信心上,这也是他们的目的。作为其中的一部分,你希望你的测试库从长远来看是可维护的,
+所以你的组件的重构(对实现的改变,但不是功能的改变)不会破坏你的测试,使你和你的团队慢下来。
+
+## 解决方案
+
+`Angular Testing Library` 是一个非常轻量级的解决方案,用于测试Angular组件。
+它在
+[`DOM Testing Library`](https://github.com/testing-library/dom-testing-library)
+的基础上提供轻量级的实用功能,以鼓励更好的测试实践。它的主要指导原则是:
+
+> [你的测试越像你的软件的使用方式,他们就越能给你信心](guiding-principles.mdx)
+
+因此,你的测试将与实际的DOM节点一起工作,而不是处理渲染的Angular组件实例。
+这个库所提供的工具便于用户以同样的方式查询DOM。通过标签文本找到表单元素(就像用户一样),
+通过文本找到链接和按钮(就像用户一样)。它还提供了一种推荐的方法,即通过 `data-testid` 来寻找元素,
+作为元素的 "逃生舱门",在这种情况下,文本内容和标签没有意义或不实用。
+
+这个库鼓励你的应用程序更容易访问,并允许你让你的测试更接近于以用户的方式使用你的组件,
+这使得你的测试给你更多的信心,当真正的用户使用它时,你的应用程序会工作。
+
+`Angular Testing Library`:
+
+- 重新导出 [`DOM Testing Library`](https://github.com/testing-library/dom-testing-library) 中的 `query` 和 `fireEvent` 实用函数。
+- 封装你的组件的 `fireEvent` 函数,在事件发生后自动调用 `detectChanges()`
+- 与测试框架无关,它可以在每个测试框架上运行。
diff --git a/i18n/zh-Hans/docusaurus-plugin-content-docs/current/bs-react-testing-library/examples.mdx b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/bs-react-testing-library/examples.mdx
new file mode 100644
index 000000000..17e2ec16e
--- /dev/null
+++ b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/bs-react-testing-library/examples.mdx
@@ -0,0 +1,133 @@
+---
+id: examples
+title: 示例
+---
+
+你可以在
+[wyze/bs-dom-testing-library/src/\_\_tests\_\_](https://github.com/wyze/bs-dom-testing-library/tree/master/src/__tests__)
+找到更多bs-dom-testing-library的例子。
+
+你可以在
+[wyze/bs-react-testing-library/src/\_\_tests\_\_](https://github.com/wyze/bs-react-testing-library/tree/master/src/__tests__)
+找到更多bs-react-testing-library的例子。
+
+## React Testing Library
+
+```reason title="Component_test.re"
+open Jest;
+open Expect;
+open ReactTestingLibrary;
+
+test("Component renders", () =>
+
+getByText(container, 'Goodbye world') // 没有匹配将抛出错误
+```
+
+上面的测试用例会失败,但是它会打印出你正在测试的 DOM 的状态,所以你会看到:
+
+```
+Unable to find an element with the text: Goodbye world. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.
+Here is the state of your container:
+
+--------------------------------------------------
+listitem:
+
+
+--------------------------------------------------
+```
diff --git a/i18n/zh-Hans/docusaurus-plugin-content-docs/current/dom-testing-library/api-events.mdx b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/dom-testing-library/api-events.mdx
new file mode 100644
index 000000000..b2ce2a3f9
--- /dev/null
+++ b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/dom-testing-library/api-events.mdx
@@ -0,0 +1,157 @@
+---
+id: api-events
+title: 触发事件
+---
+
+import Tabs from '@theme/Tabs'
+import TabItem from '@theme/TabItem'
+
+> **注意**
+>
+> 大多数项目都有一部分使用 `fireEvent` 的场景,但是大多数场景你可能应该使用
+> [`@testing-library/user-event`](user-event/intro.mdx).
+
+## `fireEvent`
+
+```typescript
+fireEvent(node: HTMLElement, event: Event)
+```
+
+触发 DOM 事件。
+
+```javascript
+//
+fireEvent(
+ getByText(container, '提交'),
+ new MouseEvent('click', {
+ bubbles: true,
+ cancelable: true,
+ }),
+)
+```
+
+## `fireEvent[eventName]`
+
+```typescript
+fireEvent[eventName](node: HTMLElement, eventProperties: Object)
+```
+
+请查看 src/event-map.js 以获得完整的列表以及默认的事件属性。
+触发 DOM 事件的快捷方式。请查看
+[src/event-map.js](https://github.com/testing-library/dom-testing-library/blob/master/src/event-map.js)
+以获得完整的列表以及默认的 `eventProperties`。
+
+**target**:当一个事件被派发到一个元素上时,该事件在一个叫做 `target` 的属性中指定元素。
+为了方便起见,如果你在eventProperties(第二个参数)中提供一个`target`属性,那么这些属性将被分配给接收事件的节点。
+
+这对一个 change 事件特别有用:
+
+```javascript
+fireEvent.change(getByLabelText(/username/i), {target: {value: 'a'}})
+
+// note: attempting to manually set the files property of an HTMLInputElement
+// results in an error as the files property is read-only.
+// this feature works around that by using Object.defineProperty.
+fireEvent.change(getByLabelText(/picture/i), {
+ target: {
+ files: [new File(['(⌐□_□)'], 'chucknorris.png', {type: 'image/png'})],
+ },
+})
+
+// Note: The 'value' attribute must use ISO 8601 format when firing a
+// change event on an input of type "date". Otherwise the element will not
+// reflect the changed value.
+
+// Invalid:
+fireEvent.change(input, {target: {value: '24/05/2020'}})
+
+// Valid:
+fireEvent.change(input, {target: {value: '2020-05-24'}})
+```
+
+**dataTransfer**:拖动事件有一个dataTransfer属性,包含在操作过程中传输的数据。
+为了方便起见,如果你在 `eventProperties`(第二个参数)中提供一个 `dataTransfer` 属性,
+那么这些属性将被添加到事件中。
+
+这应该主要用于测试拖放交互。
+
+```javascript
+fireEvent.drop(getByLabelText(/drop files here/i), {
+ dataTransfer: {
+ files: [new File(['(⌐□_□)'], 'chucknorris.png', {type: 'image/png'})],
+ },
+})
+```
+
+**Keyboard events**: 有三种与键盘输入有关的事件类型 - `keyPress`, `keyDown`, 和 `keyUp`。
+当启动这些事件时,你需要引用DOM中的一个元素和你想启动的键。
+
+```javascript
+fireEvent.keyDown(domNode, {key: 'Enter', code: 'Enter', charCode: 13})
+
+fireEvent.keyDown(domNode, {key: 'A', code: 'KeyA'})
+```
+
+你可以在 [https://www.toptal.com/developers/keycode](https://www.toptal.com/developers/keycode) 找出要使用的键码。
+
+## `createEvent[eventName]`
+
+```typescript
+createEvent[eventName](node: HTMLElement, eventProperties: Object)
+```
+
+创建DOM事件的便利方法,然后可以由 `fireEvent` 触发,允许你有一个对创建的事件的引用:
+如果你需要访问不能以编程方式启动的事件属性(如时间戳),这可能很有用。
+
+```javascript
+const myEvent = createEvent.click(node, {button: 2})
+fireEvent(node, myEvent)
+// myEvent.timeStamp can be accessed just like any other properties from myEvent
+// note: The access to the events created by `createEvent` is based on the native event API,
+// Therefore, native properties of HTMLEvent object (e.g. `timeStamp`, `cancelable`, `type`) should be set using Object.defineProperty
+// For more info see: https://developer.mozilla.org/en-US/docs/Web/API/Event
+```
+
+你还可以触发通用的事件:
+
+```javascript
+// 在 文件 input 上触发 'input' 事件
+fireEvent(
+ input,
+ createEvent('input', input, {
+ target: {files: inputFiles},
+ ...init,
+ }),
+)
+```
+
+## 使用 Jest 模拟函数
+
+[Jest的模拟函数](https://jestjs.io/docs/en/mock-functions) 可用于测试组件是否会调用
+其绑定的回调函数以响应特定的事件。
+
+
+
+
+```jsx
+import {render, screen, fireEvent} from '@testing-library/react'
+
+const Button = ({onClick, children}) => (
+
+)
+
+test('calls onClick prop when clicked', () => {
+ const handleClick = jest.fn()
+ render()
+ fireEvent.click(screen.getByText(/点击我/i))
+ expect(handleClick).toHaveBeenCalledTimes(1)
+})
+```
+
+
+
diff --git a/i18n/zh-Hans/docusaurus-plugin-content-docs/current/dom-testing-library/api-within.mdx b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/dom-testing-library/api-within.mdx
new file mode 100644
index 000000000..75d4c757d
--- /dev/null
+++ b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/dom-testing-library/api-within.mdx
@@ -0,0 +1,52 @@
+---
+id: api-within
+title: 元素内查询
+---
+
+import Tabs from '@theme/Tabs'
+import TabItem from '@theme/TabItem'
+
+`within` (`getQueriesForElement` 函数的别名) 接受一个 DOM 元素并将其绑定到原始的查询函数,
+这样你可以在不指定容器的情况下使用查询函数。React Testing Library 和 Vue Testing Library 在底层都在使用它.
+
+示例: 想要在名为 'messages' 的区域获取到文本 'hello',你可以执行以下操作:
+
+
+
+
+```js
+import {within} from '@testing-library/dom'
+
+const messages = document.getElementById('messages')
+const helloMessage = within(messages).getByText('hello')
+```
+
+
+
+
+```jsx
+import {render, within} from '@testing-library/react'
+
+const {getByText} = render()
+const messages = getByText('messages')
+const helloMessage = within(messages).getByText('hello')
+```
+
+
+
+
+```js
+cy.findByText('messages').within(() => {
+ cy.findByText('hello')
+})
+```
+
+
+
diff --git a/i18n/zh-Hans/docusaurus-plugin-content-docs/current/dom-testing-library/api.mdx b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/dom-testing-library/api.mdx
new file mode 100644
index 000000000..eedb131ab
--- /dev/null
+++ b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/dom-testing-library/api.mdx
@@ -0,0 +1,14 @@
+---
+id: api
+title: API
+---
+
+DOM Testing Library 是 Testing Library 家族的 "核心 API",所以请参照核心 API 部分获得更多详情,
+其它的库(有一些例外)都是重新导出 DOM Testing Library 的 API,以及一些其它方法
+
+
+
+- [查询](queries/about.mdx)
+- [事件](api-events.mdx)
+- [高级](api-accessibility.mdx)
+- [配置](api-configuration.mdx)
diff --git a/i18n/zh-Hans/docusaurus-plugin-content-docs/current/dom-testing-library/cheatsheet.mdx b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/dom-testing-library/cheatsheet.mdx
new file mode 100644
index 000000000..327a57c29
--- /dev/null
+++ b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/dom-testing-library/cheatsheet.mdx
@@ -0,0 +1,154 @@
+---
+id: cheatsheet
+title: 备忘单
+---
+
+`DOM Testing Library` 中所有导出函数的简短使用指南。
+
+## 查询
+
+参考 [我应该使用哪个查询函数?](queries/about.mdx#priority)
+
+| | No Match | 1 Match | 1+ Match | Await? |
+| -------------- | -------- | ------- | -------- | ------ |
+| **getBy** | throw | return | throw | No |
+| **findBy** | throw | return | throw | Yes |
+| **queryBy** | null | return | throw | No |
+| **getAllBy** | throw | array | array | No |
+| **findAllBy** | throw | array | array | Yes |
+| **queryAllBy** | [] | array | array | No |
+
+- **ByLabelText** 通过 label 或 aria-label 文本内容来查找
+ - getByLabelText
+ - queryByLabelText
+ - getAllByLabelText
+ - queryAllByLabelText
+ - findByLabelText
+ - findAllByLabelText
+- **ByPlaceholderText** 通过输入框的占位符来查找
+ - getByPlaceholderText
+ - queryByPlaceholderText
+ - getAllByPlaceholderText
+ - queryAllByPlaceholderText
+ - findByPlaceholderText
+ - findAllByPlaceholderText
+- **ByText** 通过元素的文本内容来查找
+ - getByText
+ - queryByText
+ - getAllByText
+ - queryAllByText
+ - findByText
+ - findAllByText
+- **ByDisplayValue** 通过表单元素的当前值查找
+ - getByDisplayValue
+ - queryByDisplayValue
+ - getAllByDisplayValue
+ - queryAllByDisplayValue
+ - findByDisplayValue
+ - findAllByDisplayValue
+- **ByAltText** 通过 img 的 alt 属性来查找
+ - getByAltText
+ - queryByAltText
+ - getAllByAltText
+ - queryAllByAltText
+ - findByAltText
+ - findAllByAltText
+- **ByTitle** 通过 title 属性或 svg 中的 title 标签来查找
+ - getByTitle
+ - queryByTitle
+ - getAllByTitle
+ - queryAllByTitle
+ - findByTitle
+ - findAllByTitle
+- **ByRole** 通过 aria role 来查找
+ - getByRole
+ - queryByRole
+ - getAllByRole
+ - queryAllByRole
+ - findByRole
+ - findAllByRole
+- **ByTestId** 通过 data-testid 属性来查找
+ - getByTestId
+ - queryByTestId
+ - getAllByTestId
+ - queryAllByTestId
+ - findByTestId
+ - findAllByTestId
+
+## 异步
+
+参考 [异步 API](dom-testing-library/api-async.mdx)。记得在你的测试总使用 `await` 或
+`.then()` 等待和处理异步结果。
+
+- **waitFor** (Promise) 重试回调函数直到回调函数不抛出错误或超时
+- **waitForElementToBeRemoved** (Promise) 重试回调函数直到回调函数不返回 DOM 节点
+
+> **从 v7.0.0 开始弃用:**
+>
+> - **wait** (Promise) retry the function within until it stops throwing or
+> times
+> - **waitForElement** (Promise) retry the function until it returns an element
+> or an array of elements. The `findBy` and `findAllBy` queries are async and
+> retry until the query returns successfully, or when the query times out;
+> they wrap `waitForElement`
+> - **waitForDomChange** (Promise) retry the function each time the DOM is
+> changed
+
+## 事件
+
+参考 [fireEvent 的注意事项](guide-events.mdx),
+[事件 API](api-events.mdx)
+
+- **fireEvent** 触发 DOM 事件: `fireEvent(node, event)`
+- **fireEvent.\*** 默认的事件类型
+ - **click** `fireEvent.click(node)`
+ - 参考[所有支持的事件](https://github.com/testing-library/dom-testing-library/blob/master/src/event-map.js)
+
+## 其它
+
+参考 [在元素内查询](api-within.mdx),
+[配置 API](api-configuration.mdx)
+
+- **within** 接受一个节点元素并返回所有绑定到节点的查询函数
+ (`React Testing Library` 的 render 函数就是使用它): `within(node).getByText("hello")`
+- **configure** 改变全局选项:
+ `configure({testIdAttribute: 'my-data-test-id'})`
+
+## Text Match 选项
+
+给定以下 HTML:
+
+```html
+
Hello World
+```
+
+**可以找到 div:**
+
+```javascript
+// Matching a string:
+getByText(container, 'Hello World') // full string match
+getByText(container, 'llo Worl', {exact: false}) // substring match
+getByText(container, 'hello world', {exact: false}) // ignore case
+
+// Matching a regex:
+getByText(container, /World/) // substring match
+getByText(container, /world/i) // substring match, ignore case
+getByText(container, /^hello world$/i) // full string match, ignore case
+getByText(container, /Hello W?oRlD/i) // advanced regex
+
+// Matching with a custom function:
+getByText(container, (content, element) => content.startsWith('Hello'))
+```
+
+给定一个按钮,点击后在一段时间后更新页面:
+
+```jsx
+test('loads items eventually', async () => {
+ // Click button
+ fireEvent.click(getByText(node, 'Load'))
+
+ // Wait for page to update with query text
+ const items = await findAllByText(node, /Item #[0-9]: /)
+ expect(items).toHaveLength(10)
+})
+```
diff --git a/i18n/zh-Hans/docusaurus-plugin-content-docs/current/dom-testing-library/example-intro.mdx b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/dom-testing-library/example-intro.mdx
new file mode 100644
index 000000000..538375512
--- /dev/null
+++ b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/dom-testing-library/example-intro.mdx
@@ -0,0 +1,71 @@
+---
+id: example-intro
+title: 示例
+sidebar_label: 示例
+---
+
+```js title="src/__tests__/example.js"
+// 查询 工具函数:
+import {
+ getByLabelText,
+ getByText,
+ getByTestId,
+ queryByTestId,
+ // Tip: all queries are also exposed on an object
+ // called "queries" which you could import here as well
+ waitFor,
+} from '@testing-library/dom'
+// 增加特殊的断言,如 toHaveTextContent
+import '@testing-library/jest-dom'
+
+function getExampleDOM() {
+ // This is just a raw example of setting up some DOM
+ // that we can interact with. Swap this with your UI
+ // framework of choice 😉
+ const div = document.createElement('div')
+ div.innerHTML = `
+
+
+
+ `
+ const button = div.querySelector('button')
+ const input = div.querySelector('input')
+ button.addEventListener('click', () => {
+ // let's pretend this is making a server request, so it's async
+ // (you'd want to mock this imaginary request in your unit tests)...
+ setTimeout(() => {
+ const printedUsernameContainer = document.createElement('div')
+ printedUsernameContainer.innerHTML = `
+
${input.value}
+ `
+ div.appendChild(printedUsernameContainer)
+ }, Math.floor(Math.random() * 200))
+ })
+ return div
+}
+
+test('examples of some things', async () => {
+ const famousProgrammerInHistory = 'Ada Lovelace'
+ const container = getExampleDOM()
+
+ // Get form elements by their label text.
+ // An error will be thrown if one cannot be found (accessibility FTW!)
+ const input = getByLabelText(container, 'Username')
+ input.value = famousProgrammerInHistory
+
+ // Get elements by their text, just like a real user does.
+ getByText(container, 'Print Username').click()
+
+ await waitFor(() =>
+ expect(queryByTestId(container, 'printed-username')).toBeTruthy(),
+ )
+
+ // getByTestId and queryByTestId are an escape hatch to get elements
+ // by a test id (could also attempt to get this element by its text)
+ expect(getByTestId(container, 'printed-username')).toHaveTextContent(
+ famousProgrammerInHistory,
+ )
+ // jest snapshots work great with regular DOM nodes!
+ expect(container).toMatchSnapshot()
+})
+```
diff --git a/i18n/zh-Hans/docusaurus-plugin-content-docs/current/dom-testing-library/faq.mdx b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/dom-testing-library/faq.mdx
new file mode 100644
index 000000000..58db291a4
--- /dev/null
+++ b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/dom-testing-library/faq.mdx
@@ -0,0 +1,121 @@
+---
+id: faq
+title: 常见问题
+---
+
+
+
+我应该使用哪个 get 方法?
+
+参考 [我该使用哪个查询](queries/about.mdx#优先级)
+
+
+
+
+
+我能用这个库来编写单元测试吗?
+
+绝对可以!你可以使用该库编写单元、集成和端到端测试。
+
+在编写测试时,请牢记:
+
+> 测试代码与你的软件使用方式越相似,它们能给你的信心就越大 - [2018年2月17][guiding-principle]
+
+
+
+
+
+
+ 如果应用或页面使用了国际化,无法在测试中获取到对应的文本,该怎么办?
+
+
+This is fairly common. Our first bit of advice is to try to get the default text
+used in your tests. That will make everything much easier (more than just using
+this utility). If that's not possible, then you're probably best to just stick
+with `data-testid`s (which is not bad anyway).
+
+
+
+
+
+
+ 真心不喜欢使用 data-testids,但是其它的查询方式又感觉不合适,
+ 一定要使用 data-testid 吗?
+
+
+Definitely not. That said, a common reason people don't like the `data-testid`
+attribute is they're concerned about shipping that to production. I'd suggest
+that you probably want some simple E2E tests that run in production on occasion
+to make certain that things are working smoothly. In that case the `data-testid`
+attributes will be very useful. Even if you don't run these in production, you
+may want to run some E2E tests that run on the same code you're about to ship to
+production. In that case, the `data-testid` attributes will be valuable there as
+well.
+
+All that said, if you really don't want to ship `data-testid` attributes, then
+you can use
+[this simple babel plugin](https://www.npmjs.com/package/babel-plugin-react-remove-properties)
+to remove them.
+
+If you don't want to use them at all, then you can simply use regular DOM
+methods and properties to query elements off your container.
+
+```javascript
+const firstLiInDiv = container.querySelector('div li')
+const allLisInDiv = container.querySelectorAll('div li')
+const rootElement = container.firstChild
+```
+
+
+
+
+
+
+ 如果在一个列表中为每一项都添加了 data-testid="item" 属性,怎么样区分它们?
+
+
+You can make your selector just choose the one you want by including :nth-child
+in the selector.
+
+```javascript
+const thirdLiInUl = container.querySelector('ul > li:nth-child(3)')
+```
+
+Or you could use `getAllByRole` to query the `listitem` role and access the
+index in question:
+
+```javascript
+const items = [
+ /* your items */
+]
+const {container} = render(/* however you render this stuff */)
+const thirdItem = getAllByRole(container, 'listitem')[2]
+```
+
+
+
+
+
+ 求救! 无法访问组件的方法或组件实例!
+
+
+This is **intentional**.
+
+We want you to focus on testing the output and functionality of the component as
+it is observed by the user and to **avoid worrying about the implementation
+details** of the component.
+
+We believe this leads to less brittle and more meaningful test code.
+
+Please refer to the [Guiding Principles](guiding-principles.mdx) of this testing
+library for more info.
+
+
+
+
+
+
+
+[guiding-principle]: https://twitter.com/kentcdodds/status/977018512689455106
+
+
diff --git a/i18n/zh-Hans/docusaurus-plugin-content-docs/current/dom-testing-library/install.mdx b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/dom-testing-library/install.mdx
new file mode 100644
index 000000000..ef3fbcc8b
--- /dev/null
+++ b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/dom-testing-library/install.mdx
@@ -0,0 +1,60 @@
+---
+id: install
+title: 安装
+sidebar_label: 安装
+---
+
+```bash npm2yarn
+npm install --save-dev @testing-library/dom
+```
+
+## 封装器
+
+如果你在使用像 React 这样的框架或库时,你应该安装对应的封装器:
+
+- [React Testing Library](react-testing-library/intro.mdx)
+- [Reason Testing Library](bs-react-testing-library/intro.mdx)
+- [React Native Testing Library](react-native-testing-library/intro.mdx)
+- [Vue Testing Library](vue-testing-library/intro.mdx)
+- [Marko Testing Library](marko-testing-library/intro.mdx)
+- [Angular Testing Library](angular-testing-library/intro.mdx)
+- [Preact Testing Library](preact-testing-library/intro.mdx)
+- [Svelte Testing Library](svelte-testing-library/intro.mdx)
+- [Cypress Testing Library](cypress-testing-library/intro.mdx)
+- [Puppeteer Testing Library](pptr-testing-library/intro.mdx)
+- [Testcafe Testing Library](testcafe-testing-library/intro.mdx)
+- [Nightwatch Testing Library](nightwatch-testing-library/intro.mdx)
+
+## 生态
+
+`DOM Testing Library` 和下面这些配套库一起运行:
+
+- [user-event](user-event/intro.mdx) 模拟浏览器事件
+- [jest-dom](ecosystem-jest-dom.mdx) 自定义的 Jest 匹配器
+- [bs-jest-dom](ecosystem-bs-jest-dom.mdx) `bs-react-testing-library` 的配套库
+- [jest-native](ecosystem-jest-native.mdx) `React Native Testing Library` 的配套库
+- [react-select-event](ecosystem-react-select-event.mdx) `React Testing Library` 的配套库
+- [eslint-plugin-testing-library](ecosystem-eslint-plugin-testing-library.mdx)
+ Testing Library 的 ESLint 插件
+- [eslint-plugin-jest-dom](ecosystem-eslint-plugin-jest-dom.mdx) Jest DOM 的 ESLint 插件
+- [riot-testing-library](ecosystem-riot-testing-library.mdx) 支持 Riot.js 组件
+
+## Main Exports
+
+你可以查看
+[`DOM Testing Library` 的 package.json](https://unpkg.com/@testing-library/dom/package.json).
+
+特别是,`main`、`module`和`umd:main`字段很有用。每个字段都指向一个在某些情况下有用的文件。
+通常情况下,你的测试框架会根据你的情况解析到正确的文件,但如果它没有,那么你可以配置你的测试框架,
+在你 require/import `@testing-library/dom` 时解析到正确的文件,或者你可以更明确地导入你需要的文件。举例:
+
+```js
+import {within} from '@testing-library/dom/dist/@testing-library/dom.umd.js'
+```
+
+你可以在
+[这里](https://unpkg.com/@testing-library/dom/dist/)
+查看已发布的dist文件。
+
+`main` 文件被配置为支持 `package.json` `engines.node`字段中引用的node的版本。
+但 `module` 和 `umd:main` 文件被配置为支持IE10(旧的浏览器)。
diff --git a/i18n/zh-Hans/docusaurus-plugin-content-docs/current/dom-testing-library/intro.mdx b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/dom-testing-library/intro.mdx
new file mode 100644
index 000000000..4f9e22dfb
--- /dev/null
+++ b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/dom-testing-library/intro.mdx
@@ -0,0 +1,34 @@
+---
+id: intro
+title: 简介
+---
+
+## 问题
+
+想要编写可维护的测试代码,希望它们可以增加你对组件正常工作的信心。为了实现此目标, 您希望你的测试避免包含实现细节,
+以便组件的重构(对实现的更改但不是功能的更改)时不会破坏原有的测试,进而减慢团队的开发速度。
+
+## 解决方案
+
+`DOM Testing Library` 是一个轻量级的解决方案,用于测试 DOM 节点
+(由 [`JSDOM`](https://github.com/jsdom/jsdom)/[Jest][jest]模拟或真正的浏览器)。
+它提供的查询DOM节点工具和真正用户在页面查找元素时相似的,从而提升你对 UI 代码的信心。
+`DOM Testing Library` 的第一指导原则是:
+
+> [测试代码与你的软件使用方式越相似,它们能给你的信心就越大](guiding-principles.mdx)
+
+作为该目标的一部分,该库提供的工具函数有助于实现以用户的方式来查询 DOM。
+通过标签文本来查找表单上的元素 (就像用户那样),通过文本找到对应链接和按钮 (就像用户那样) 等等。
+当文本内容和标签不适用的情况下,它推荐使用 `data-testid` 作为 “逃生舱” 来查找元素。
+
+该库鼓励你的应用应该易于访问(无障碍访问),并让你的测试更接近你的组件被用户使用,
+从而让你对组件在用户手中正常工作更加有信心。
+
+**Testing Library 不是什么**:
+
+1. 测试执行器 或 框架
+2. 特定的测试框架 (尽管我们推荐 Jest 作为首选项,
+ 但是该库适用于其它框架. 参考
+ [不使用 Jest](setup.mdx#using-without-jest))
+
+[jest]: https://jestjs.io
diff --git a/i18n/zh-Hans/docusaurus-plugin-content-docs/current/dom-testing-library/setup.mdx b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/dom-testing-library/setup.mdx
new file mode 100644
index 000000000..3e652d4d4
--- /dev/null
+++ b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/dom-testing-library/setup.mdx
@@ -0,0 +1,31 @@
+---
+id: setup
+title: 设置
+sidebar_label: 设置
+---
+
+如果你的测试代码是使用 webpack(或类似的) 打包运行在浏览器中,则 `DOM Testing Library` 是开箱即用的。
+但是,大多数人都是结合
+[Jest 测试框架](https://jestjs.io/) 一起使用,同时设置 Jest 的 `testEnvironment` 为
+[`jest-environment-jsdom`](https://www.npmjs.com/package/jest-environment-jsdom)
+
+## 不使用 Jest
+
+[jsdom](https://github.com/jsdom/jsdom) 是使用纯 Javascript 对 DOM 和浏览器 API 在 node 上的实现。
+如果你没有使用 Jest,且想要在 node 环境中测试,你需要自己安装 jsdom。
+同时还有一个名为
+[global-jsdom](https://github.com/modosc/global-jsdom) 的库帮助你设置全局的环境来模拟浏览器 API。
+注意,如果你在使用 Vitest,则你不需要安装 global-jsdom,你只需配置 [`environment`](https://vitest.dev/config/#environment)
+为 `jsdom` 即可。
+
+首先安装 jsdom 和 global-jsdom。
+
+```bash npm2yarn
+npm install --save-dev jsdom global-jsdom
+```
+
+使用 mocha 的情况下,测试命令应该如下:
+
+```
+mocha --require global-jsdom/register
+```
diff --git a/i18n/zh-Hans/docusaurus-plugin-content-docs/current/ecosystem-bs-jest-dom.mdx b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/ecosystem-bs-jest-dom.mdx
new file mode 100644
index 000000000..5510b63fd
--- /dev/null
+++ b/i18n/zh-Hans/docusaurus-plugin-content-docs/current/ecosystem-bs-jest-dom.mdx
@@ -0,0 +1,58 @@
+---
+id: ecosystem-bs-jest-dom
+title: bs-jest-dom
+---
+
+[`bs-jest-dom`][gh] 是 [`bs-react-testing-library`](bs-react-testing-library/intro.mdx) 的配套库,
+通过 [BuckleScript][bucklescript] 为 [ReasonML][re] 中的Jest提供自定义DOM元素匹配器。
+
+```bash npm2yarn
+npm install --save-dev bs-jest-dom
+```
+
+- [bs-jest-dom on GitHub][gh]
+
+请查阅[jest-dom的文档](https://github.com/testing-library/jest-dom),了解可用匹配器的完整列表。
+
+[gh]: https://github.com/wyze/bs-jest-dom
+
+## 设置
+
+```json
+{
+ "bs-dev-dependencies": ["bs-jest-dom"]
+}
+```
+
+## 示例
+
+```reason title="A_test.re"
+open Jest;
+open JestDom;
+open ReactTestingLibrary;
+
+module Heading = {
+ let component = ReasonReact.statelessComponent("Heading");
+
+ let make = (~text, _children) => {
+ ...component,
+ render: _self =>
+