From 192da81913a2f86ca9540550dfd0af2fadfde7ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Fri, 25 Mar 2022 15:56:43 +0000 Subject: [PATCH] Deploy website - based on 1360b73295fcb8db0e2ec6b2eccd4b7c4704567a --- 404.html | 4 ++-- 7ad239b9.67f31575.js | 1 + 7ad239b9.70d08b7d.js | 1 - 8a6052eb.c4fc724d.js => 8a6052eb.c3de18ed.js | 2 +- c8229a80.43c80a18.js | 1 - c8229a80.562e0255.js | 1 + docs/api-queries/index.html | 20 ++++++++----------- docs/api/index.html | 12 +++++------ docs/eslint-plugin-testing-library/index.html | 4 ++-- docs/getting-started/index.html | 12 +++++------ docs/how-should-i-query/index.html | 10 +++++----- docs/migration-v2/index.html | 4 ++-- docs/migration-v7/index.html | 4 ++-- docs/migration-v9/index.html | 4 ++-- docs/react-navigation/index.html | 4 ++-- docs/redux-integration/index.html | 4 ++-- f2d2b077.9f8a1547.js | 1 - f2d2b077.a566c08c.js | 1 + index.html | 4 ++-- ...in.da14aa78.js => runtime~main.6f8f5c93.js | 2 +- search/index.html | 4 ++-- 21 files changed, 48 insertions(+), 52 deletions(-) create mode 100644 7ad239b9.67f31575.js delete mode 100644 7ad239b9.70d08b7d.js rename 8a6052eb.c4fc724d.js => 8a6052eb.c3de18ed.js (98%) delete mode 100644 c8229a80.43c80a18.js create mode 100644 c8229a80.562e0255.js delete mode 100644 f2d2b077.9f8a1547.js create mode 100644 f2d2b077.a566c08c.js rename runtime~main.da14aa78.js => runtime~main.6f8f5c93.js (94%) diff --git a/404.html b/404.html index 1aa04123..cb9fdbe4 100644 --- a/404.html +++ b/404.html @@ -6,14 +6,14 @@ Page Not Found | React Native Testing Library - +

Page Not Found

We could not find what you were looking for.

Please contact the owner of the site that linked you to the original URL and let them know their link is broken.

- + \ No newline at end of file diff --git a/7ad239b9.67f31575.js b/7ad239b9.67f31575.js new file mode 100644 index 00000000..2214c53a --- /dev/null +++ b/7ad239b9.67f31575.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[8],{66:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return r})),n.d(t,"metadata",(function(){return c})),n.d(t,"rightToc",(function(){return o})),n.d(t,"default",(function(){return s}));var a=n(1),i=n(6),l=(n(0),n(80)),r={id:"api-queries",title:"Queries"},c={unversionedId:"api-queries",id:"api-queries",isDocsHomePage:!1,title:"Queries",description:"Variants",source:"@site/docs/Queries.md",permalink:"/react-native-testing-library/docs/api-queries",editUrl:"https://github.com/callstack/react-native-testing-library/blob/main/docs/Queries.md",sidebar:"docs",previous:{title:"API",permalink:"/react-native-testing-library/docs/api"},next:{title:"Migration to 9.0",permalink:"/react-native-testing-library/docs/migration-v9"}},o=[{value:"Variants",id:"variants",children:[{value:"getBy",id:"getby",children:[]},{value:"getAllBy",id:"getallby",children:[]},{value:"queryBy",id:"queryby",children:[]},{value:"queryAllBy",id:"queryallby",children:[]},{value:"findBy",id:"findby",children:[]},{value:"findAllBy",id:"findallby",children:[]}]},{value:"Queries",id:"queries",children:[{value:"Options",id:"options",children:[]},{value:"ByText",id:"bytext",children:[]},{value:"ByPlaceholderText",id:"byplaceholdertext",children:[]},{value:"ByDisplayValue",id:"bydisplayvalue",children:[]},{value:"ByTestId",id:"bytestid",children:[]},{value:"ByLabelText",id:"bylabeltext",children:[]},{value:"ByA11yHint, ByAccessibilityHint, ByHintText",id:"bya11yhint-byaccessibilityhint-byhinttext",children:[]},{value:"ByA11yStates, ByAccessibilityStates",id:"bya11ystates-byaccessibilitystates",children:[]},{value:"ByRole",id:"byrole",children:[]},{value:"ByA11yState, ByAccessibilityState",id:"bya11ystate-byaccessibilitystate",children:[]},{value:"ByA11Value, ByAccessibilityValue",id:"bya11value-byaccessibilityvalue",children:[]}]},{value:"TextMatch",id:"textmatch",children:[{value:"Examples",id:"examples",children:[]},{value:"Precision",id:"precision",children:[]},{value:"Normalization",id:"normalization",children:[]}]},{value:"Unit testing helpers",id:"unit-testing-helpers",children:[{value:"UNSAFE_ByType",id:"unsafe_bytype",children:[]},{value:"UNSAFE_ByProps",id:"unsafe_byprops",children:[]}]}],b={rightToc:o};function s(e){var t=e.components,n=Object(i.a)(e,["components"]);return Object(l.b)("wrapper",Object(a.a)({},b,n,{components:t,mdxType:"MDXLayout"}),Object(l.b)("h2",{id:"variants"},"Variants"),Object(l.b)("blockquote",null,Object(l.b)("p",{parentName:"blockquote"},Object(l.b)("inlineCode",{parentName:"p"},"getBy")," queries are shown by default in the ",Object(l.b)("a",Object(a.a)({parentName:"p"},{href:"#queries"}),"query documentation"),"\nbelow.")),Object(l.b)("h3",{id:"getby"},"getBy"),Object(l.b)("p",null,Object(l.b)("inlineCode",{parentName:"p"},"getBy*")," queries return the first matching node for a query, and throw an error if no elements match or if more than one match is found (use ",Object(l.b)("inlineCode",{parentName:"p"},"getAllBy")," instead)."),Object(l.b)("h3",{id:"getallby"},"getAllBy"),Object(l.b)("p",null,Object(l.b)("inlineCode",{parentName:"p"},"getAllBy*")," queries return an array of all matching nodes for a query, and throw an error if no elements match."),Object(l.b)("h3",{id:"queryby"},"queryBy"),Object(l.b)("p",null,Object(l.b)("inlineCode",{parentName:"p"},"queryBy*")," queries return the first matching node for a query, and return ",Object(l.b)("inlineCode",{parentName:"p"},"null")," if no elements match. This is useful for asserting an element that is not present. This throws if more than one match is found (use ",Object(l.b)("inlineCode",{parentName:"p"},"queryAllBy")," instead)."),Object(l.b)("h3",{id:"queryallby"},"queryAllBy"),Object(l.b)("p",null,Object(l.b)("inlineCode",{parentName:"p"},"queryAllBy*")," queries return an array of all matching nodes for a query, and return an empty array (",Object(l.b)("inlineCode",{parentName:"p"},"[]"),") if no elements match."),Object(l.b)("h3",{id:"findby"},"findBy"),Object(l.b)("p",null,Object(l.b)("inlineCode",{parentName:"p"},"findBy")," queries return a promise which resolves when a matching element is found. The promise is rejected if no elements match or if more than one match is found after a default timeout of 4500ms. If you need to find more than one element, then use ",Object(l.b)("inlineCode",{parentName:"p"},"findAllBy"),"."),Object(l.b)("h3",{id:"findallby"},"findAllBy"),Object(l.b)("p",null,Object(l.b)("inlineCode",{parentName:"p"},"findAllBy")," queries return a promise which resolves to an array when any matching elements are found. The promise is rejected if no elements match after a default timeout of 4500ms."),Object(l.b)("div",{className:"admonition admonition-info alert alert--info"},Object(l.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-heading"}),Object(l.b)("h5",{parentName:"div"},Object(l.b)("span",Object(a.a)({parentName:"h5"},{className:"admonition-icon"}),Object(l.b)("svg",Object(a.a)({parentName:"span"},{xmlns:"http://www.w3.org/2000/svg",width:"14",height:"16",viewBox:"0 0 14 16"}),Object(l.b)("path",Object(a.a)({parentName:"svg"},{fillRule:"evenodd",d:"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"})))),"info")),Object(l.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-content"}),Object(l.b)("p",{parentName:"div"},"In order to properly use ",Object(l.b)("inlineCode",{parentName:"p"},"findBy")," and ",Object(l.b)("inlineCode",{parentName:"p"},"findAllBy")," queries you need at least React >=16.9.0 (featuring async ",Object(l.b)("inlineCode",{parentName:"p"},"act"),") or React Native >=0.61 (which comes with React >=16.9.0)."))),Object(l.b)("div",{className:"admonition admonition-info alert alert--info"},Object(l.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-heading"}),Object(l.b)("h5",{parentName:"div"},Object(l.b)("span",Object(a.a)({parentName:"h5"},{className:"admonition-icon"}),Object(l.b)("svg",Object(a.a)({parentName:"span"},{xmlns:"http://www.w3.org/2000/svg",width:"14",height:"16",viewBox:"0 0 14 16"}),Object(l.b)("path",Object(a.a)({parentName:"svg"},{fillRule:"evenodd",d:"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"})))),"info")),Object(l.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-content"}),Object(l.b)("p",{parentName:"div"},Object(l.b)("inlineCode",{parentName:"p"},"findBy")," and ",Object(l.b)("inlineCode",{parentName:"p"},"findAllBy")," queries accept optional ",Object(l.b)("inlineCode",{parentName:"p"},"waitForOptions")," object argument which can contain ",Object(l.b)("inlineCode",{parentName:"p"},"timeout")," and ",Object(l.b)("inlineCode",{parentName:"p"},"interval")," properies which have the same meaning as respective options for ",Object(l.b)("a",Object(a.a)({parentName:"p"},{href:"api#waitfor"}),Object(l.b)("inlineCode",{parentName:"a"},"waitFor"))," function."))),Object(l.b)("h2",{id:"queries"},"Queries"),Object(l.b)("p",null,Object(l.b)("em",{parentName:"p"},"Note: most methods like this one return a ",Object(l.b)("a",Object(a.a)({parentName:"em"},{href:"https://reactjs.org/docs/test-renderer.html#testinstance"}),Object(l.b)("inlineCode",{parentName:"a"},"ReactTestInstance"))," with following properties that you may be interested in:")),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-typescript"}),"type ReactTestInstance = {\n type: string | Function;\n props: { [propName: string]: any };\n parent: null | ReactTestInstance;\n children: Array;\n};\n")),Object(l.b)("h3",{id:"options"},"Options"),Object(l.b)("p",null,"Query first argument can be a ",Object(l.b)("strong",{parentName:"p"},"string")," or a ",Object(l.b)("strong",{parentName:"p"},"regex"),". Some queries accept optional argument which change string matching behaviour. See ",Object(l.b)("a",Object(a.a)({parentName:"p"},{href:"#textmatch"}),"TextMatch")," for more info."),Object(l.b)("h3",{id:"bytext"},Object(l.b)("inlineCode",{parentName:"h3"},"ByText")),Object(l.b)("blockquote",null,Object(l.b)("p",{parentName:"blockquote"},"getByText, getAllByText, queryByText, queryAllByText, findByText, findAllByText")),Object(l.b)("p",null,"Returns a ",Object(l.b)("inlineCode",{parentName:"p"},"ReactTestInstance")," with matching text \u2013 may be a string or regular expression."),Object(l.b)("p",null,"This method will join ",Object(l.b)("inlineCode",{parentName:"p"},"")," siblings to find matches, similarly to ",Object(l.b)("a",Object(a.a)({parentName:"p"},{href:"https://reactnative.dev/docs/text#containers"}),"how React Native handles these components"),". This will allow for querying for strings that will be visually rendered together, but may be semantically separate React components."),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"import { render } from '@testing-library/react-native';\n\nconst { getByText } = render();\nconst element = getByText('banana');\n")),Object(l.b)("h3",{id:"byplaceholdertext"},Object(l.b)("inlineCode",{parentName:"h3"},"ByPlaceholderText")),Object(l.b)("blockquote",null,Object(l.b)("p",{parentName:"blockquote"},"getByPlaceholderText, getAllByPlaceholderText, queryByPlaceholderText, queryAllByPlaceholderText, findByPlaceholderText, findAllByPlaceholderText")),Object(l.b)("p",null,"Returns a ",Object(l.b)("inlineCode",{parentName:"p"},"ReactTestInstance")," for a ",Object(l.b)("inlineCode",{parentName:"p"},"TextInput")," with a matching placeholder \u2013 may be a string or regular expression."),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"import { render } from '@testing-library/react-native';\n\nconst { getByPlaceholderText } = render();\nconst element = getByPlaceholderText('username');\n")),Object(l.b)("h3",{id:"bydisplayvalue"},Object(l.b)("inlineCode",{parentName:"h3"},"ByDisplayValue")),Object(l.b)("blockquote",null,Object(l.b)("p",{parentName:"blockquote"},"getByDisplayValue, getAllByDisplayValue, queryByDisplayValue, queryAllByDisplayValue, findByDisplayValue, findAllByDisplayValue")),Object(l.b)("p",null,"Returns a ",Object(l.b)("inlineCode",{parentName:"p"},"ReactTestInstance")," for a ",Object(l.b)("inlineCode",{parentName:"p"},"TextInput")," with a matching display value \u2013 may be a string or regular expression."),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"import { render } from '@testing-library/react-native';\n\nconst { getByDisplayValue } = render();\nconst element = getByDisplayValue('username');\n")),Object(l.b)("h3",{id:"bytestid"},Object(l.b)("inlineCode",{parentName:"h3"},"ByTestId")),Object(l.b)("blockquote",null,Object(l.b)("p",{parentName:"blockquote"},"getByTestId, getAllByTestId, queryByTestId, queryAllByTestId, findByTestId, findAllByTestId")),Object(l.b)("p",null,"Returns a ",Object(l.b)("inlineCode",{parentName:"p"},"ReactTestInstance")," with matching ",Object(l.b)("inlineCode",{parentName:"p"},"testID")," prop. ",Object(l.b)("inlineCode",{parentName:"p"},"testID")," \u2013 may be a string or a regular expression."),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"import { render } from '@testing-library/react-native';\n\nconst { getByTestId } = render();\nconst element = getByTestId('unique-id');\n")),Object(l.b)("div",{className:"admonition admonition-info alert alert--info"},Object(l.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-heading"}),Object(l.b)("h5",{parentName:"div"},Object(l.b)("span",Object(a.a)({parentName:"h5"},{className:"admonition-icon"}),Object(l.b)("svg",Object(a.a)({parentName:"span"},{xmlns:"http://www.w3.org/2000/svg",width:"14",height:"16",viewBox:"0 0 14 16"}),Object(l.b)("path",Object(a.a)({parentName:"svg"},{fillRule:"evenodd",d:"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"})))),"info")),Object(l.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-content"}),Object(l.b)("p",{parentName:"div"},"In the spirit of ",Object(l.b)("a",Object(a.a)({parentName:"p"},{href:"https://testing-library.com/docs/guiding-principles"}),"the guiding principles"),", it is recommended to use this only after the other queries don't work for your use case. Using ",Object(l.b)("inlineCode",{parentName:"p"},"testID")," attributes do not resemble how your software is used and should be avoided if possible. However, they are particularly useful for end-to-end testing on real devices, e.g. using Detox and it's an encouraged technique to use there. Learn more from the blog post ",Object(l.b)("a",Object(a.a)({parentName:"p"},{href:"https://kentcdodds.com/blog/making-your-ui-tests-resilient-to-change"}),'"Making your UI tests resilient to change"'),"."))),Object(l.b)("h3",{id:"bylabeltext"},Object(l.b)("inlineCode",{parentName:"h3"},"ByLabelText")),Object(l.b)("blockquote",null,Object(l.b)("p",{parentName:"blockquote"},"getByLabelText, getAllByLabelText, queryByLabelText, queryAllByLabelText, findByLabelText, findAllByLabelText")),Object(l.b)("p",null,"Returns a ",Object(l.b)("inlineCode",{parentName:"p"},"ReactTestInstance")," with matching ",Object(l.b)("inlineCode",{parentName:"p"},"accessibilityLabel")," prop."),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"import { render } from '@testing-library/react-native';\n\nconst { getByLabelText } = render();\nconst element = getByLabelText('my-label');\n")),Object(l.b)("h3",{id:"bya11yhint-byaccessibilityhint-byhinttext"},Object(l.b)("inlineCode",{parentName:"h3"},"ByA11yHint"),", ",Object(l.b)("inlineCode",{parentName:"h3"},"ByAccessibilityHint"),", ",Object(l.b)("inlineCode",{parentName:"h3"},"ByHintText")),Object(l.b)("blockquote",null,Object(l.b)("p",{parentName:"blockquote"},"getByA11yHint, getAllByA11yHint, queryByA11yHint, queryAllByA11yHint, findByA11yHint, findAllByA11yHint\ngetByAccessibilityHint, getAllByAccessibilityHint, queryByAccessibilityHint, queryAllByAccessibilityHint, findByAccessibilityHint, findAllByAccessibilityHint\ngetByHintText, getAllByHintText, queryByHintText, queryAllByHintText, findByHintText, findAllByHintText")),Object(l.b)("p",null,"Returns a ",Object(l.b)("inlineCode",{parentName:"p"},"ReactTestInstance")," with matching ",Object(l.b)("inlineCode",{parentName:"p"},"accessibilityHint")," prop."),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"import { render } from '@testing-library/react-native';\n\nconst { getByHintText } = render();\nconst element = getByHintText('Plays a song');\n")),Object(l.b)("div",{className:"admonition admonition-info alert alert--info"},Object(l.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-heading"}),Object(l.b)("h5",{parentName:"div"},Object(l.b)("span",Object(a.a)({parentName:"h5"},{className:"admonition-icon"}),Object(l.b)("svg",Object(a.a)({parentName:"span"},{xmlns:"http://www.w3.org/2000/svg",width:"14",height:"16",viewBox:"0 0 14 16"}),Object(l.b)("path",Object(a.a)({parentName:"svg"},{fillRule:"evenodd",d:"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"})))),"info")),Object(l.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-content"}),Object(l.b)("p",{parentName:"div"},"Please consult ",Object(l.b)("a",Object(a.a)({parentName:"p"},{href:"https://developer.apple.com/documentation/objectivec/nsobject/1615093-accessibilityhint"}),"Apple guidelines on how ",Object(l.b)("inlineCode",{parentName:"a"},"accessibilityHint")," should be used"),"."))),Object(l.b)("h3",{id:"bya11ystates-byaccessibilitystates"},Object(l.b)("inlineCode",{parentName:"h3"},"ByA11yStates"),", ",Object(l.b)("inlineCode",{parentName:"h3"},"ByAccessibilityStates")),Object(l.b)("blockquote",null,Object(l.b)("p",{parentName:"blockquote"},"getByA11yStates, getAllByA11yStates, queryByA11yStates, queryAllByA11yStates\ngetByAccessibilityStates, getAllByAccessibilityStates, queryByAccessibilityStates, queryAllByAccessibilityStates")),Object(l.b)("p",null,"Returns a ",Object(l.b)("inlineCode",{parentName:"p"},"ReactTestInstance")," with matching ",Object(l.b)("inlineCode",{parentName:"p"},"accessibilityStates")," prop."),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"import { render } from '@testing-library/react-native';\n\nconst { getByA11yStates } = render();\nconst element = getByA11yStates(['checked']);\nconst element2 = getByA11yStates('checked');\n")),Object(l.b)("h3",{id:"byrole"},Object(l.b)("inlineCode",{parentName:"h3"},"ByRole")),Object(l.b)("blockquote",null,Object(l.b)("p",{parentName:"blockquote"},"getByRole, getAllByRole, queryByRole, queryAllByRole, findByRole, findAllByRole")),Object(l.b)("p",null,"Returns a ",Object(l.b)("inlineCode",{parentName:"p"},"ReactTestInstance")," with matching ",Object(l.b)("inlineCode",{parentName:"p"},"accessibilityRole")," prop."),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"import { render } from '@testing-library/react-native';\n\nconst { getByRole } = render();\nconst element = getByRole('button');\n")),Object(l.b)("h3",{id:"bya11ystate-byaccessibilitystate"},Object(l.b)("inlineCode",{parentName:"h3"},"ByA11yState"),", ",Object(l.b)("inlineCode",{parentName:"h3"},"ByAccessibilityState")),Object(l.b)("blockquote",null,Object(l.b)("p",{parentName:"blockquote"},"getByA11yState, getAllByA11yState, queryByA11yState, queryAllByA11yState, findByA11yState, findAllByA11yState\ngetByAccessibilityState, getAllByAccessibilityState, queryByAccessibilityState, queryAllByAccessibilityState, findByAccessibilityState, findAllByAccessibilityState")),Object(l.b)("p",null,"Returns a ",Object(l.b)("inlineCode",{parentName:"p"},"ReactTestInstance")," with matching ",Object(l.b)("inlineCode",{parentName:"p"},"accessibilityState")," prop."),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"import { render } from '@testing-library/react-native';\n\nconst { getByA11yState } = render();\nconst element = getByA11yState({ disabled: true });\n")),Object(l.b)("h3",{id:"bya11value-byaccessibilityvalue"},Object(l.b)("inlineCode",{parentName:"h3"},"ByA11Value"),", ",Object(l.b)("inlineCode",{parentName:"h3"},"ByAccessibilityValue")),Object(l.b)("blockquote",null,Object(l.b)("p",{parentName:"blockquote"},"getByA11yValue, getAllByA11yValue, queryByA11yValue, queryAllByA11yValue, findByA11yValue, findAllByA11yValue\ngetByAccessibilityValue, getAllByAccessibilityValue, queryByAccessibilityValue, queryAllByAccessibilityValue, findByAccessibilityValue, findAllByAccessibilityValue")),Object(l.b)("p",null,"Returns a ",Object(l.b)("inlineCode",{parentName:"p"},"ReactTestInstance")," with matching ",Object(l.b)("inlineCode",{parentName:"p"},"accessibilityValue")," prop."),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"import { render } from '@testing-library/react-native';\n\nconst { getByA11yValue } = render();\nconst element = getByA11yValue({ min: 40 });\n")),Object(l.b)("h2",{id:"textmatch"},"TextMatch"),Object(l.b)("p",null,"Most of the query APIs take a ",Object(l.b)("inlineCode",{parentName:"p"},"TextMatch")," as an argument, which means the argument can be either a ",Object(l.b)("em",{parentName:"p"},"string")," or ",Object(l.b)("em",{parentName:"p"},"regex"),"."),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-typescript"}),"type TextMatchOptions = {\n exact?: boolean;\n normalizer?: (textToNormalize: string) => string;\n trim?: boolean;\n collapseWhitespace?: boolean;\n};\n")),Object(l.b)("h3",{id:"examples"},"Examples"),Object(l.b)("p",null,"Given the following render:"),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"const { getByText } = render(Hello World);\n")),Object(l.b)("p",null,"Will ",Object(l.b)("strong",{parentName:"p"},"find a match"),":"),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-js"}),"// Matching a string:\ngetByText('Hello World'); // full string match\ngetByText('llo Worl', { exact: false }); // substring match\ngetByText('hello world', { exact: false }); // ignore case-sensitivity\n\n// Matching a regex:\ngetByText(/World/); // substring match\ngetByText(/world/i); // substring match, ignore case\ngetByText(/^hello world$/i); // full string match, ignore case-sensitivity\ngetByText(/Hello W?oRlD/i); // advanced regex\n")),Object(l.b)("p",null,"Will ",Object(l.b)("strong",{parentName:"p"},"NOT find a match")),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-js"}),"// substring does not match\ngetByText('llo Worl');\n// full string does not match\ngetByText('Goodbye World');\n\n// case-sensitive regex with different case\ngetByText(/hello world/);\n")),Object(l.b)("h3",{id:"precision"},"Precision"),Object(l.b)("p",null,"Queries that take a ",Object(l.b)("inlineCode",{parentName:"p"},"TextMatch")," also accept an object as the final argument that can contain options that affect the precision of string matching:"),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"exact"),": Defaults to ",Object(l.b)("inlineCode",{parentName:"li"},"true"),"; matches full strings, case-sensitive. When false, matches substrings and is not case-sensitive.",Object(l.b)("ul",{parentName:"li"},Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"exact")," has no effect on regex argument."),Object(l.b)("li",{parentName:"ul"},"In most cases using a ",Object(l.b)("inlineCode",{parentName:"li"},"regex")," instead of a string gives you more control over fuzzy matching and should be preferred over ",Object(l.b)("inlineCode",{parentName:"li"},"{ exact: false }"),"."))),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"normalizer"),": An optional function which overrides normalization behavior. See ",Object(l.b)("a",Object(a.a)({parentName:"li"},{href:"#normalization"}),"Normalization"),".")),Object(l.b)("p",null,Object(l.b)("inlineCode",{parentName:"p"},"exact")," option defaults to ",Object(l.b)("inlineCode",{parentName:"p"},"true")," but if you want to search for a text slice or make text matching case-insensitive you can override it. That being said we advise you to use regex in more complex scenarios."),Object(l.b)("h3",{id:"normalization"},"Normalization"),Object(l.b)("p",null,"Before running any matching logic against text, it is automatically normalized. By default, normalization consists of trimming whitespace from the start and end of text, and collapsing multiple adjacent whitespace characters into a single space."),Object(l.b)("p",null,"If you want to prevent that normalization, or provide alternative normalization (e.g. to remove Unicode control characters), you can provide a ",Object(l.b)("inlineCode",{parentName:"p"},"normalizer")," function in the options object. This function will be given a string and is expected to return a normalized version of that string."),Object(l.b)("div",{className:"admonition admonition-info alert alert--info"},Object(l.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-heading"}),Object(l.b)("h5",{parentName:"div"},Object(l.b)("span",Object(a.a)({parentName:"h5"},{className:"admonition-icon"}),Object(l.b)("svg",Object(a.a)({parentName:"span"},{xmlns:"http://www.w3.org/2000/svg",width:"14",height:"16",viewBox:"0 0 14 16"}),Object(l.b)("path",Object(a.a)({parentName:"svg"},{fillRule:"evenodd",d:"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"})))),"info")),Object(l.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-content"}),Object(l.b)("p",{parentName:"div"},"Specifying a value for ",Object(l.b)("inlineCode",{parentName:"p"},"normalizer")," replaces the built-in normalization, but you can call ",Object(l.b)("inlineCode",{parentName:"p"},"getDefaultNormalizer")," to obtain a built-in normalizer, either to adjust that normalization or to call it from your own normalizer."))),Object(l.b)("p",null,Object(l.b)("inlineCode",{parentName:"p"},"getDefaultNormalizer")," take options object which allows the selection of behaviour:"),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"trim"),": Defaults to ",Object(l.b)("inlineCode",{parentName:"li"},"true"),". Trims leading and trailing whitespace."),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"collapseWhitespace"),": Defaults to ",Object(l.b)("inlineCode",{parentName:"li"},"true"),". Collapses inner whitespace (newlines, tabs repeated spaces) into a single space.")),Object(l.b)("h4",{id:"normalization-examples"},"Normalization Examples"),Object(l.b)("p",null,"To perform a match against text without trimming:"),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-typescript"}),"getByText(node, 'text', {\n normalizer: getDefaultNormalizer({ trim: false }),\n});\n")),Object(l.b)("p",null,"To override normalization to remove some Unicode characters whilst keeping some (but not all) of the built-in normalization behavior:"),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-typescript"}),"getByText(node, 'text', {\n normalizer: (str) =>\n getDefaultNormalizer({ trim: false })(str).replace(/[\\u200E-\\u200F]*/g, ''),\n});\n")),Object(l.b)("h2",{id:"unit-testing-helpers"},"Unit testing helpers"),Object(l.b)("blockquote",null,Object(l.b)("p",{parentName:"blockquote"},"Use sparingly and responsibly, escape hatches here")),Object(l.b)("p",null,Object(l.b)("inlineCode",{parentName:"p"},"render")," from ",Object(l.b)("inlineCode",{parentName:"p"},"@testing-library/react-native")," exposes additional queries that ",Object(l.b)("strong",{parentName:"p"},"should not be used in component integration testing"),", but some users (like component library creators) interested in unit testing some components may find helpful."),Object(l.b)("details",null,Object(l.b)("summary",null,"Queries helpful in unit testing"),Object(l.b)("p",null,"The interface is the same as for other queries, but we won't provide full names so that they're harder to find by search engines."),Object(l.b)("h3",{id:"unsafe_bytype"},Object(l.b)("inlineCode",{parentName:"h3"},"UNSAFE_ByType")),Object(l.b)("blockquote",null,Object(l.b)("p",{parentName:"blockquote"},"UNSAFE_getByType, UNSAFE_getAllByType, UNSAFE_queryByType, UNSAFE_queryAllByType")),Object(l.b)("p",null,"Returns a ",Object(l.b)("inlineCode",{parentName:"p"},"ReactTestInstance")," with matching a React component type."),Object(l.b)("div",{className:"admonition admonition-caution alert alert--warning"},Object(l.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-heading"}),Object(l.b)("h5",{parentName:"div"},Object(l.b)("span",Object(a.a)({parentName:"h5"},{className:"admonition-icon"}),Object(l.b)("svg",Object(a.a)({parentName:"span"},{xmlns:"http://www.w3.org/2000/svg",width:"16",height:"16",viewBox:"0 0 16 16"}),Object(l.b)("path",Object(a.a)({parentName:"svg"},{fillRule:"evenodd",d:"M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"})))),"caution")),Object(l.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-content"}),Object(l.b)("p",{parentName:"div"},"This method has been marked unsafe, since it requires knowledge about implementation details of the component. Use responsibly."))),Object(l.b)("h3",{id:"unsafe_byprops"},Object(l.b)("inlineCode",{parentName:"h3"},"UNSAFE_ByProps")),Object(l.b)("blockquote",null,Object(l.b)("p",{parentName:"blockquote"},"UNSAFE_getByProps, UNSAFE_getAllByProps, UNSAFE_queryByProps, UNSAFE_queryAllByProps")),Object(l.b)("p",null,"Returns a ",Object(l.b)("inlineCode",{parentName:"p"},"ReactTestInstance")," with matching props object."),Object(l.b)("div",{className:"admonition admonition-caution alert alert--warning"},Object(l.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-heading"}),Object(l.b)("h5",{parentName:"div"},Object(l.b)("span",Object(a.a)({parentName:"h5"},{className:"admonition-icon"}),Object(l.b)("svg",Object(a.a)({parentName:"span"},{xmlns:"http://www.w3.org/2000/svg",width:"16",height:"16",viewBox:"0 0 16 16"}),Object(l.b)("path",Object(a.a)({parentName:"svg"},{fillRule:"evenodd",d:"M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"})))),"caution")),Object(l.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-content"}),Object(l.b)("p",{parentName:"div"},"This method has been marked unsafe, since it requires knowledge about implementation details of the component. Use responsibly.")))))}s.isMDXComponent=!0},80:function(e,t,n){"use strict";n.d(t,"a",(function(){return p})),n.d(t,"b",(function(){return y}));var a=n(0),i=n.n(a);function l(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function c(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var b=i.a.createContext({}),s=function(e){var t=i.a.useContext(b),n=t;return e&&(n="function"==typeof e?e(t):c({},t,{},e)),n},p=function(e){var t=s(e.components);return i.a.createElement(b.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return i.a.createElement(i.a.Fragment,{},t)}},m=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,l=e.originalType,r=e.parentName,b=o(e,["components","mdxType","originalType","parentName"]),p=s(n),m=a,y=p["".concat(r,".").concat(m)]||p[m]||d[m]||l;return n?i.a.createElement(y,c({ref:t},b,{components:n})):i.a.createElement(y,c({ref:t},b))}));function y(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var l=n.length,r=new Array(l);r[0]=m;var c={};for(var o in t)hasOwnProperty.call(t,o)&&(c[o]=t[o]);c.originalType=e,c.mdxType="string"==typeof e?e:a,r[1]=c;for(var b=2;bByText",id:"bytext",children:[]},{value:"ByPlaceholderText",id:"byplaceholdertext",children:[]},{value:"ByDisplayValue",id:"bydisplayvalue",children:[]},{value:"ByTestId",id:"bytestid",children:[]},{value:"ByA11yLabel, ByAccessibilityLabel, ByLabelText",id:"bya11ylabel-byaccessibilitylabel-bylabeltext",children:[]},{value:"ByA11yHint, ByAccessibilityHint, ByHintText",id:"bya11yhint-byaccessibilityhint-byhinttext",children:[]},{value:"ByA11yStates, ByAccessibilityStates",id:"bya11ystates-byaccessibilitystates",children:[]},{value:"ByA11yRole, ByAccessibilityRole, ByRole",id:"bya11yrole-byaccessibilityrole-byrole",children:[]},{value:"ByA11yState, ByAccessibilityState",id:"bya11ystate-byaccessibilitystate",children:[]},{value:"ByA11Value, ByAccessibilityValue",id:"bya11value-byaccessibilityvalue",children:[]}]},{value:"TextMatch",id:"textmatch",children:[{value:"Examples",id:"examples",children:[]},{value:"Precision",id:"precision",children:[]},{value:"Normalization",id:"normalization",children:[]}]},{value:"Unit testing helpers",id:"unit-testing-helpers",children:[{value:"UNSAFE_ByType",id:"unsafe_bytype",children:[]},{value:"UNSAFE_ByProps",id:"unsafe_byprops",children:[]}]}],b={rightToc:o};function s(e){var t=e.components,n=Object(i.a)(e,["components"]);return Object(l.b)("wrapper",Object(a.a)({},b,n,{components:t,mdxType:"MDXLayout"}),Object(l.b)("h2",{id:"variants"},"Variants"),Object(l.b)("blockquote",null,Object(l.b)("p",{parentName:"blockquote"},Object(l.b)("inlineCode",{parentName:"p"},"getBy")," queries are shown by default in the ",Object(l.b)("a",Object(a.a)({parentName:"p"},{href:"#queries"}),"query documentation"),"\nbelow.")),Object(l.b)("h3",{id:"getby"},"getBy"),Object(l.b)("p",null,Object(l.b)("inlineCode",{parentName:"p"},"getBy*")," queries return the first matching node for a query, and throw an error if no elements match or if more than one match is found (use ",Object(l.b)("inlineCode",{parentName:"p"},"getAllBy")," instead)."),Object(l.b)("h3",{id:"getallby"},"getAllBy"),Object(l.b)("p",null,Object(l.b)("inlineCode",{parentName:"p"},"getAllBy*")," queries return an array of all matching nodes for a query, and throw an error if no elements match."),Object(l.b)("h3",{id:"queryby"},"queryBy"),Object(l.b)("p",null,Object(l.b)("inlineCode",{parentName:"p"},"queryBy*")," queries return the first matching node for a query, and return ",Object(l.b)("inlineCode",{parentName:"p"},"null")," if no elements match. This is useful for asserting an element that is not present. This throws if more than one match is found (use ",Object(l.b)("inlineCode",{parentName:"p"},"queryAllBy")," instead)."),Object(l.b)("h3",{id:"queryallby"},"queryAllBy"),Object(l.b)("p",null,Object(l.b)("inlineCode",{parentName:"p"},"queryAllBy*")," queries return an array of all matching nodes for a query, and return an empty array (",Object(l.b)("inlineCode",{parentName:"p"},"[]"),") if no elements match."),Object(l.b)("h3",{id:"findby"},"findBy"),Object(l.b)("p",null,Object(l.b)("inlineCode",{parentName:"p"},"findBy")," queries return a promise which resolves when a matching element is found. The promise is rejected if no elements match or if more than one match is found after a default timeout of 4500ms. If you need to find more than one element, then use ",Object(l.b)("inlineCode",{parentName:"p"},"findAllBy"),"."),Object(l.b)("h3",{id:"findallby"},"findAllBy"),Object(l.b)("p",null,Object(l.b)("inlineCode",{parentName:"p"},"findAllBy")," queries return a promise which resolves to an array when any matching elements are found. The promise is rejected if no elements match after a default timeout of 4500ms."),Object(l.b)("div",{className:"admonition admonition-info alert alert--info"},Object(l.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-heading"}),Object(l.b)("h5",{parentName:"div"},Object(l.b)("span",Object(a.a)({parentName:"h5"},{className:"admonition-icon"}),Object(l.b)("svg",Object(a.a)({parentName:"span"},{xmlns:"http://www.w3.org/2000/svg",width:"14",height:"16",viewBox:"0 0 14 16"}),Object(l.b)("path",Object(a.a)({parentName:"svg"},{fillRule:"evenodd",d:"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"})))),"info")),Object(l.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-content"}),Object(l.b)("p",{parentName:"div"},"In order to properly use ",Object(l.b)("inlineCode",{parentName:"p"},"findBy")," and ",Object(l.b)("inlineCode",{parentName:"p"},"findAllBy")," queries you need at least React >=16.9.0 (featuring async ",Object(l.b)("inlineCode",{parentName:"p"},"act"),") or React Native >=0.61 (which comes with React >=16.9.0)."))),Object(l.b)("div",{className:"admonition admonition-info alert alert--info"},Object(l.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-heading"}),Object(l.b)("h5",{parentName:"div"},Object(l.b)("span",Object(a.a)({parentName:"h5"},{className:"admonition-icon"}),Object(l.b)("svg",Object(a.a)({parentName:"span"},{xmlns:"http://www.w3.org/2000/svg",width:"14",height:"16",viewBox:"0 0 14 16"}),Object(l.b)("path",Object(a.a)({parentName:"svg"},{fillRule:"evenodd",d:"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"})))),"info")),Object(l.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-content"}),Object(l.b)("p",{parentName:"div"},Object(l.b)("inlineCode",{parentName:"p"},"findBy")," and ",Object(l.b)("inlineCode",{parentName:"p"},"findAllBy")," queries accept optional ",Object(l.b)("inlineCode",{parentName:"p"},"waitForOptions")," object argument which can contain ",Object(l.b)("inlineCode",{parentName:"p"},"timeout")," and ",Object(l.b)("inlineCode",{parentName:"p"},"interval")," properies which have the same meaning as respective options for ",Object(l.b)("a",Object(a.a)({parentName:"p"},{href:"api#waitfor"}),Object(l.b)("inlineCode",{parentName:"a"},"waitFor"))," function."))),Object(l.b)("h2",{id:"queries"},"Queries"),Object(l.b)("p",null,Object(l.b)("em",{parentName:"p"},"Note: most methods like this one return a ",Object(l.b)("a",Object(a.a)({parentName:"em"},{href:"https://reactjs.org/docs/test-renderer.html#testinstance"}),Object(l.b)("inlineCode",{parentName:"a"},"ReactTestInstance"))," with following properties that you may be interested in:")),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-typescript"}),"type ReactTestInstance = {\n type: string | Function;\n props: { [propName: string]: any };\n parent: null | ReactTestInstance;\n children: Array;\n};\n")),Object(l.b)("h3",{id:"options"},"Options"),Object(l.b)("p",null,"Query first argument can be a ",Object(l.b)("strong",{parentName:"p"},"string")," or a ",Object(l.b)("strong",{parentName:"p"},"regex"),". Some queries accept optional argument which change string matching behaviour. See ",Object(l.b)("a",Object(a.a)({parentName:"p"},{href:"#textmatch"}),"TextMatch")," for more info."),Object(l.b)("h3",{id:"bytext"},Object(l.b)("inlineCode",{parentName:"h3"},"ByText")),Object(l.b)("blockquote",null,Object(l.b)("p",{parentName:"blockquote"},"getByText, getAllByText, queryByText, queryAllByText, findByText, findAllByText")),Object(l.b)("p",null,"Returns a ",Object(l.b)("inlineCode",{parentName:"p"},"ReactTestInstance")," with matching text \u2013 may be a string or regular expression."),Object(l.b)("p",null,"This method will join ",Object(l.b)("inlineCode",{parentName:"p"},"")," siblings to find matches, similarly to ",Object(l.b)("a",Object(a.a)({parentName:"p"},{href:"https://reactnative.dev/docs/text#containers"}),"how React Native handles these components"),". This will allow for querying for strings that will be visually rendered together, but may be semantically separate React components."),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"import { render } from '@testing-library/react-native';\n\nconst { getByText } = render();\nconst element = getByText('banana');\n")),Object(l.b)("h3",{id:"byplaceholdertext"},Object(l.b)("inlineCode",{parentName:"h3"},"ByPlaceholderText")),Object(l.b)("blockquote",null,Object(l.b)("p",{parentName:"blockquote"},"getByPlaceholderText, getAllByPlaceholderText, queryByPlaceholderText, queryAllByPlaceholderText, findByPlaceholderText, findAllByPlaceholderText")),Object(l.b)("p",null,"Returns a ",Object(l.b)("inlineCode",{parentName:"p"},"ReactTestInstance")," for a ",Object(l.b)("inlineCode",{parentName:"p"},"TextInput")," with a matching placeholder \u2013 may be a string or regular expression."),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"import { render } from '@testing-library/react-native';\n\nconst { getByPlaceholderText } = render();\nconst element = getByPlaceholderText('username');\n")),Object(l.b)("h3",{id:"bydisplayvalue"},Object(l.b)("inlineCode",{parentName:"h3"},"ByDisplayValue")),Object(l.b)("blockquote",null,Object(l.b)("p",{parentName:"blockquote"},"getByDisplayValue, getAllByDisplayValue, queryByDisplayValue, queryAllByDisplayValue, findByDisplayValue, findAllByDisplayValue")),Object(l.b)("p",null,"Returns a ",Object(l.b)("inlineCode",{parentName:"p"},"ReactTestInstance")," for a ",Object(l.b)("inlineCode",{parentName:"p"},"TextInput")," with a matching display value \u2013 may be a string or regular expression."),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"import { render } from '@testing-library/react-native';\n\nconst { getByDisplayValue } = render();\nconst element = getByDisplayValue('username');\n")),Object(l.b)("h3",{id:"bytestid"},Object(l.b)("inlineCode",{parentName:"h3"},"ByTestId")),Object(l.b)("blockquote",null,Object(l.b)("p",{parentName:"blockquote"},"getByTestId, getAllByTestId, queryByTestId, queryAllByTestId, findByTestId, findAllByTestId")),Object(l.b)("p",null,"Returns a ",Object(l.b)("inlineCode",{parentName:"p"},"ReactTestInstance")," with matching ",Object(l.b)("inlineCode",{parentName:"p"},"testID")," prop. ",Object(l.b)("inlineCode",{parentName:"p"},"testID")," \u2013 may be a string or a regular expression."),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"import { render } from '@testing-library/react-native';\n\nconst { getByTestId } = render();\nconst element = getByTestId('unique-id');\n")),Object(l.b)("div",{className:"admonition admonition-info alert alert--info"},Object(l.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-heading"}),Object(l.b)("h5",{parentName:"div"},Object(l.b)("span",Object(a.a)({parentName:"h5"},{className:"admonition-icon"}),Object(l.b)("svg",Object(a.a)({parentName:"span"},{xmlns:"http://www.w3.org/2000/svg",width:"14",height:"16",viewBox:"0 0 14 16"}),Object(l.b)("path",Object(a.a)({parentName:"svg"},{fillRule:"evenodd",d:"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"})))),"info")),Object(l.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-content"}),Object(l.b)("p",{parentName:"div"},"In the spirit of ",Object(l.b)("a",Object(a.a)({parentName:"p"},{href:"https://testing-library.com/docs/guiding-principles"}),"the guiding principles"),", it is recommended to use this only after the other queries don't work for your use case. Using ",Object(l.b)("inlineCode",{parentName:"p"},"testID")," attributes do not resemble how your software is used and should be avoided if possible. However, they are particularly useful for end-to-end testing on real devices, e.g. using Detox and it's an encouraged technique to use there. Learn more from the blog post ",Object(l.b)("a",Object(a.a)({parentName:"p"},{href:"https://kentcdodds.com/blog/making-your-ui-tests-resilient-to-change"}),'"Making your UI tests resilient to change"'),"."))),Object(l.b)("h3",{id:"bya11ylabel-byaccessibilitylabel-bylabeltext"},Object(l.b)("inlineCode",{parentName:"h3"},"ByA11yLabel"),", ",Object(l.b)("inlineCode",{parentName:"h3"},"ByAccessibilityLabel"),", ",Object(l.b)("inlineCode",{parentName:"h3"},"ByLabelText")),Object(l.b)("blockquote",null,Object(l.b)("p",{parentName:"blockquote"},"getByA11yLabel, getAllByA11yLabel, queryByA11yLabel, queryAllByA11yLabel, findByA11yLabel, findAllByA11yLabel\ngetByAccessibilityLabel, getAllByAccessibilityLabel, queryByAccessibilityLabel, queryAllByAccessibilityLabel, findByAccessibilityLabel, findAllByAccessibilityLabel\ngetByLabelText, getAllByLabelText, queryByLabelText, queryAllByLabelText, findByLabelText, findAllByLabelText")),Object(l.b)("p",null,"Returns a ",Object(l.b)("inlineCode",{parentName:"p"},"ReactTestInstance")," with matching ",Object(l.b)("inlineCode",{parentName:"p"},"accessibilityLabel")," prop."),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"import { render } from '@testing-library/react-native';\n\nconst { getByLabelText } = render();\nconst element = getByLabelText('my-label');\n")),Object(l.b)("h3",{id:"bya11yhint-byaccessibilityhint-byhinttext"},Object(l.b)("inlineCode",{parentName:"h3"},"ByA11yHint"),", ",Object(l.b)("inlineCode",{parentName:"h3"},"ByAccessibilityHint"),", ",Object(l.b)("inlineCode",{parentName:"h3"},"ByHintText")),Object(l.b)("blockquote",null,Object(l.b)("p",{parentName:"blockquote"},"getByA11yHint, getAllByA11yHint, queryByA11yHint, queryAllByA11yHint, findByA11yHint, findAllByA11yHint\ngetByAccessibilityHint, getAllByAccessibilityHint, queryByAccessibilityHint, queryAllByAccessibilityHint, findByAccessibilityHint, findAllByAccessibilityHint\ngetByHintText, getAllByHintText, queryByHintText, queryAllByHintText, findByHintText, findAllByHintText")),Object(l.b)("p",null,"Returns a ",Object(l.b)("inlineCode",{parentName:"p"},"ReactTestInstance")," with matching ",Object(l.b)("inlineCode",{parentName:"p"},"accessibilityHint")," prop."),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"import { render } from '@testing-library/react-native';\n\nconst { getByHintText } = render();\nconst element = getByHintText('Plays a song');\n")),Object(l.b)("div",{className:"admonition admonition-info alert alert--info"},Object(l.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-heading"}),Object(l.b)("h5",{parentName:"div"},Object(l.b)("span",Object(a.a)({parentName:"h5"},{className:"admonition-icon"}),Object(l.b)("svg",Object(a.a)({parentName:"span"},{xmlns:"http://www.w3.org/2000/svg",width:"14",height:"16",viewBox:"0 0 14 16"}),Object(l.b)("path",Object(a.a)({parentName:"svg"},{fillRule:"evenodd",d:"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"})))),"info")),Object(l.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-content"}),Object(l.b)("p",{parentName:"div"},"Please consult ",Object(l.b)("a",Object(a.a)({parentName:"p"},{href:"https://developer.apple.com/documentation/objectivec/nsobject/1615093-accessibilityhint"}),"Apple guidelines on how ",Object(l.b)("inlineCode",{parentName:"a"},"accessibilityHint")," should be used"),"."))),Object(l.b)("h3",{id:"bya11ystates-byaccessibilitystates"},Object(l.b)("inlineCode",{parentName:"h3"},"ByA11yStates"),", ",Object(l.b)("inlineCode",{parentName:"h3"},"ByAccessibilityStates")),Object(l.b)("blockquote",null,Object(l.b)("p",{parentName:"blockquote"},"getByA11yStates, getAllByA11yStates, queryByA11yStates, queryAllByA11yStates\ngetByAccessibilityStates, getAllByAccessibilityStates, queryByAccessibilityStates, queryAllByAccessibilityStates")),Object(l.b)("p",null,"Returns a ",Object(l.b)("inlineCode",{parentName:"p"},"ReactTestInstance")," with matching ",Object(l.b)("inlineCode",{parentName:"p"},"accessibilityStates")," prop."),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"import { render } from '@testing-library/react-native';\n\nconst { getByA11yStates } = render();\nconst element = getByA11yStates(['checked']);\nconst element2 = getByA11yStates('checked');\n")),Object(l.b)("h3",{id:"bya11yrole-byaccessibilityrole-byrole"},Object(l.b)("inlineCode",{parentName:"h3"},"ByA11yRole"),", ",Object(l.b)("inlineCode",{parentName:"h3"},"ByAccessibilityRole"),", ",Object(l.b)("inlineCode",{parentName:"h3"},"ByRole")),Object(l.b)("blockquote",null,Object(l.b)("p",{parentName:"blockquote"},"getByA11yRole, getAllByA11yRole, queryByA11yRole, queryAllByA11yRole, findByA11yRole, findAllByA11yRole\ngetByAccessibilityRole, getAllByAccessibilityRole, queryByAccessibilityRole, queryAllByAccessibilityRole, findByAccessibilityRole, findAllByAccessibilityRole\ngetByRole, getAllByRole, queryByRole, queryAllByRole, findByRole, findAllByRole")),Object(l.b)("p",null,"Returns a ",Object(l.b)("inlineCode",{parentName:"p"},"ReactTestInstance")," with matching ",Object(l.b)("inlineCode",{parentName:"p"},"accessibilityRole")," prop."),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"import { render } from '@testing-library/react-native';\n\nconst { getByA11yRole } = render();\nconst element = getByA11yRole('button');\n")),Object(l.b)("h3",{id:"bya11ystate-byaccessibilitystate"},Object(l.b)("inlineCode",{parentName:"h3"},"ByA11yState"),", ",Object(l.b)("inlineCode",{parentName:"h3"},"ByAccessibilityState")),Object(l.b)("blockquote",null,Object(l.b)("p",{parentName:"blockquote"},"getByA11yState, getAllByA11yState, queryByA11yState, queryAllByA11yState, findByA11yState, findAllByA11yState\ngetByAccessibilityState, getAllByAccessibilityState, queryByAccessibilityState, queryAllByAccessibilityState, findByAccessibilityState, findAllByAccessibilityState")),Object(l.b)("p",null,"Returns a ",Object(l.b)("inlineCode",{parentName:"p"},"ReactTestInstance")," with matching ",Object(l.b)("inlineCode",{parentName:"p"},"accessibilityState")," prop."),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"import { render } from '@testing-library/react-native';\n\nconst { getByA11yState } = render();\nconst element = getByA11yState({ disabled: true });\n")),Object(l.b)("h3",{id:"bya11value-byaccessibilityvalue"},Object(l.b)("inlineCode",{parentName:"h3"},"ByA11Value"),", ",Object(l.b)("inlineCode",{parentName:"h3"},"ByAccessibilityValue")),Object(l.b)("blockquote",null,Object(l.b)("p",{parentName:"blockquote"},"getByA11yValue, getAllByA11yValue, queryByA11yValue, queryAllByA11yValue, findByA11yValue, findAllByA11yValue\ngetByAccessibilityValue, getAllByAccessibilityValue, queryByAccessibilityValue, queryAllByAccessibilityValue, findByAccessibilityValue, findAllByAccessibilityValue")),Object(l.b)("p",null,"Returns a ",Object(l.b)("inlineCode",{parentName:"p"},"ReactTestInstance")," with matching ",Object(l.b)("inlineCode",{parentName:"p"},"accessibilityValue")," prop."),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"import { render } from '@testing-library/react-native';\n\nconst { getByA11yValue } = render();\nconst element = getByA11yValue({ min: 40 });\n")),Object(l.b)("h2",{id:"textmatch"},"TextMatch"),Object(l.b)("p",null,"Most of the query APIs take a ",Object(l.b)("inlineCode",{parentName:"p"},"TextMatch")," as an argument, which means the argument can be either a ",Object(l.b)("em",{parentName:"p"},"string")," or ",Object(l.b)("em",{parentName:"p"},"regex"),"."),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-typescript"}),"type TextMatchOptions = {\n exact?: boolean;\n normalizer?: (textToNormalize: string) => string;\n trim?: boolean;\n collapseWhitespace?: boolean;\n};\n")),Object(l.b)("h3",{id:"examples"},"Examples"),Object(l.b)("p",null,"Given the following render:"),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"const { getByText } = render(Hello World);\n")),Object(l.b)("p",null,"Will ",Object(l.b)("strong",{parentName:"p"},"find a match"),":"),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-js"}),"// Matching a string:\ngetByText('Hello World'); // full string match\ngetByText('llo Worl', { exact: false }); // substring match\ngetByText('hello world', { exact: false }); // ignore case-sensitivity\n\n// Matching a regex:\ngetByText(/World/); // substring match\ngetByText(/world/i); // substring match, ignore case\ngetByText(/^hello world$/i); // full string match, ignore case-sensitivity\ngetByText(/Hello W?oRlD/i); // advanced regex\n")),Object(l.b)("p",null,"Will ",Object(l.b)("strong",{parentName:"p"},"NOT find a match")),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-js"}),"// substring does not match\ngetByText('llo Worl');\n// full string does not match\ngetByText('Goodbye World');\n\n// case-sensitive regex with different case\ngetByText(/hello world/);\n")),Object(l.b)("h3",{id:"precision"},"Precision"),Object(l.b)("p",null,"Queries that take a ",Object(l.b)("inlineCode",{parentName:"p"},"TextMatch")," also accept an object as the final argument that can contain options that affect the precision of string matching:"),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"exact"),": Defaults to ",Object(l.b)("inlineCode",{parentName:"li"},"true"),"; matches full strings, case-sensitive. When false, matches substrings and is not case-sensitive.",Object(l.b)("ul",{parentName:"li"},Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"exact")," has no effect on regex argument."),Object(l.b)("li",{parentName:"ul"},"In most cases using a ",Object(l.b)("inlineCode",{parentName:"li"},"regex")," instead of a string gives you more control over fuzzy matching and should be preferred over ",Object(l.b)("inlineCode",{parentName:"li"},"{ exact: false }"),"."))),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"normalizer"),": An optional function which overrides normalization behavior. See ",Object(l.b)("a",Object(a.a)({parentName:"li"},{href:"#normalization"}),"Normalization"),".")),Object(l.b)("p",null,Object(l.b)("inlineCode",{parentName:"p"},"exact")," option defaults to ",Object(l.b)("inlineCode",{parentName:"p"},"true")," but if you want to search for a text slice or make text matching case-insensitive you can override it. That being said we advise you to use regex in more complex scenarios."),Object(l.b)("h3",{id:"normalization"},"Normalization"),Object(l.b)("p",null,"Before running any matching logic against text, it is automatically normalized. By default, normalization consists of trimming whitespace from the start and end of text, and collapsing multiple adjacent whitespace characters into a single space."),Object(l.b)("p",null,"If you want to prevent that normalization, or provide alternative normalization (e.g. to remove Unicode control characters), you can provide a ",Object(l.b)("inlineCode",{parentName:"p"},"normalizer")," function in the options object. This function will be given a string and is expected to return a normalized version of that string."),Object(l.b)("div",{className:"admonition admonition-info alert alert--info"},Object(l.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-heading"}),Object(l.b)("h5",{parentName:"div"},Object(l.b)("span",Object(a.a)({parentName:"h5"},{className:"admonition-icon"}),Object(l.b)("svg",Object(a.a)({parentName:"span"},{xmlns:"http://www.w3.org/2000/svg",width:"14",height:"16",viewBox:"0 0 14 16"}),Object(l.b)("path",Object(a.a)({parentName:"svg"},{fillRule:"evenodd",d:"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"})))),"info")),Object(l.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-content"}),Object(l.b)("p",{parentName:"div"},"Specifying a value for ",Object(l.b)("inlineCode",{parentName:"p"},"normalizer")," replaces the built-in normalization, but you can call ",Object(l.b)("inlineCode",{parentName:"p"},"getDefaultNormalizer")," to obtain a built-in normalizer, either to adjust that normalization or to call it from your own normalizer."))),Object(l.b)("p",null,Object(l.b)("inlineCode",{parentName:"p"},"getDefaultNormalizer")," take options object which allows the selection of behaviour:"),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"trim"),": Defaults to ",Object(l.b)("inlineCode",{parentName:"li"},"true"),". Trims leading and trailing whitespace."),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"collapseWhitespace"),": Defaults to ",Object(l.b)("inlineCode",{parentName:"li"},"true"),". Collapses inner whitespace (newlines, tabs repeated spaces) into a single space.")),Object(l.b)("h4",{id:"normalization-examples"},"Normalization Examples"),Object(l.b)("p",null,"To perform a match against text without trimming:"),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-typescript"}),"getByText(node, 'text', {\n normalizer: getDefaultNormalizer({ trim: false }),\n});\n")),Object(l.b)("p",null,"To override normalization to remove some Unicode characters whilst keeping some (but not all) of the built-in normalization behavior:"),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-typescript"}),"getByText(node, 'text', {\n normalizer: (str) =>\n getDefaultNormalizer({ trim: false })(str).replace(/[\\u200E-\\u200F]*/g, ''),\n});\n")),Object(l.b)("h2",{id:"unit-testing-helpers"},"Unit testing helpers"),Object(l.b)("blockquote",null,Object(l.b)("p",{parentName:"blockquote"},"Use sparingly and responsibly, escape hatches here")),Object(l.b)("p",null,Object(l.b)("inlineCode",{parentName:"p"},"render")," from ",Object(l.b)("inlineCode",{parentName:"p"},"@testing-library/react-native")," exposes additional queries that ",Object(l.b)("strong",{parentName:"p"},"should not be used in component integration testing"),", but some users (like component library creators) interested in unit testing some components may find helpful."),Object(l.b)("details",null,Object(l.b)("summary",null,"Queries helpful in unit testing"),Object(l.b)("p",null,"The interface is the same as for other queries, but we won't provide full names so that they're harder to find by search engines."),Object(l.b)("h3",{id:"unsafe_bytype"},Object(l.b)("inlineCode",{parentName:"h3"},"UNSAFE_ByType")),Object(l.b)("blockquote",null,Object(l.b)("p",{parentName:"blockquote"},"UNSAFE_getByType, UNSAFE_getAllByType, UNSAFE_queryByType, UNSAFE_queryAllByType")),Object(l.b)("p",null,"Returns a ",Object(l.b)("inlineCode",{parentName:"p"},"ReactTestInstance")," with matching a React component type."),Object(l.b)("div",{className:"admonition admonition-caution alert alert--warning"},Object(l.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-heading"}),Object(l.b)("h5",{parentName:"div"},Object(l.b)("span",Object(a.a)({parentName:"h5"},{className:"admonition-icon"}),Object(l.b)("svg",Object(a.a)({parentName:"span"},{xmlns:"http://www.w3.org/2000/svg",width:"16",height:"16",viewBox:"0 0 16 16"}),Object(l.b)("path",Object(a.a)({parentName:"svg"},{fillRule:"evenodd",d:"M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"})))),"caution")),Object(l.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-content"}),Object(l.b)("p",{parentName:"div"},"This method has been marked unsafe, since it requires knowledge about implementation details of the component. Use responsibly."))),Object(l.b)("h3",{id:"unsafe_byprops"},Object(l.b)("inlineCode",{parentName:"h3"},"UNSAFE_ByProps")),Object(l.b)("blockquote",null,Object(l.b)("p",{parentName:"blockquote"},"UNSAFE_getByProps, UNSAFE_getAllByProps, UNSAFE_queryByProps, UNSAFE_queryAllByProps")),Object(l.b)("p",null,"Returns a ",Object(l.b)("inlineCode",{parentName:"p"},"ReactTestInstance")," with matching props object."),Object(l.b)("div",{className:"admonition admonition-caution alert alert--warning"},Object(l.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-heading"}),Object(l.b)("h5",{parentName:"div"},Object(l.b)("span",Object(a.a)({parentName:"h5"},{className:"admonition-icon"}),Object(l.b)("svg",Object(a.a)({parentName:"span"},{xmlns:"http://www.w3.org/2000/svg",width:"16",height:"16",viewBox:"0 0 16 16"}),Object(l.b)("path",Object(a.a)({parentName:"svg"},{fillRule:"evenodd",d:"M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"})))),"caution")),Object(l.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-content"}),Object(l.b)("p",{parentName:"div"},"This method has been marked unsafe, since it requires knowledge about implementation details of the component. Use responsibly.")))))}s.isMDXComponent=!0},80:function(e,t,n){"use strict";n.d(t,"a",(function(){return p})),n.d(t,"b",(function(){return m}));var a=n(0),i=n.n(a);function l(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function c(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var b=i.a.createContext({}),s=function(e){var t=i.a.useContext(b),n=t;return e&&(n="function"==typeof e?e(t):r({},t,{},e)),n},p=function(e){var t=s(e.components);return i.a.createElement(b.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return i.a.createElement(i.a.Fragment,{},t)}},y=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,l=e.originalType,c=e.parentName,b=o(e,["components","mdxType","originalType","parentName"]),p=s(n),y=a,m=p["".concat(c,".").concat(y)]||p[y]||d[y]||l;return n?i.a.createElement(m,r({ref:t},b,{components:n})):i.a.createElement(m,r({ref:t},b))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var l=n.length,c=new Array(l);c[0]=y;var r={};for(var o in t)hasOwnProperty.call(t,o)&&(r[o]=t[o]);r.originalType=e,r.mdxType="string"==typeof e?e:a,c[1]=r;for(var b=2;b=16.9.0 (featuring async ",Object(i.b)("inlineCode",{parentName:"p"},"act"),") or React Native >=0.61 (which comes with React >=16.9.0)."))),Object(i.b)("h3",{id:"additional-jest-matchers"},"Additional Jest matchers"),Object(i.b)("p",null,"In order to use addtional React Native-specific jest matchers from ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/testing-library/jest-native"}),"@testing-library/jest-native")," package add it to your project:"),Object(i.b)("h4",{id:"using-yarn-1"},"Using ",Object(i.b)("inlineCode",{parentName:"h4"},"yarn")),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-sh"}),"yarn add --dev @testing-library/jest-native\n")),Object(i.b)("h4",{id:"using-npm-1"},"Using ",Object(i.b)("inlineCode",{parentName:"h4"},"npm")),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-sh"}),"npm install --save-dev @testing-library/jest-native\n")),Object(i.b)("p",null,"Then automatically add it to your jest tests by using ",Object(i.b)("inlineCode",{parentName:"p"},"setupFilesAfterEnv")," option in your Jest configuration (it's usually located either in ",Object(i.b)("inlineCode",{parentName:"p"},"package.json")," under ",Object(i.b)("inlineCode",{parentName:"p"},'"jest"')," key or in a ",Object(i.b)("inlineCode",{parentName:"p"},"jest.config.js")," file):"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-json"}),'{\n "preset": "react-native",\n "setupFilesAfterEnv": ["@testing-library/jest-native/extend-expect"]\n}\n')),Object(i.b)("h3",{id:"flow"},"Flow"),Object(i.b)("p",null,"Note for ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"https://flow.org"}),"Flow")," users \u2013 you'll also need to install typings for ",Object(i.b)("inlineCode",{parentName:"p"},"react-test-renderer"),":"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-sh"}),"flow-typed install react-test-renderer\n")),Object(i.b)("h2",{id:"example"},"Example"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"import { render, fireEvent } from '@testing-library/react-native';\nimport { QuestionsBoard } from '../QuestionsBoard';\n\ntest('form submits two answers', () => {\n const allQuestions = ['q1', 'q2'];\n const mockFn = jest.fn();\n\n const { getAllByA11yLabel, getByText } = render(\n \n );\n\n const answerInputs = getAllByA11yLabel('answer input');\n\n fireEvent.changeText(answerInputs[0], 'a1');\n fireEvent.changeText(answerInputs[1], 'a2');\n fireEvent.press(getByText('Submit'));\n\n expect(mockFn).toBeCalledWith({\n '1': { q: 'q1', a: 'a1' },\n '2': { q: 'q2', a: 'a2' },\n });\n});\n")),Object(i.b)("p",null,"You can find the source of ",Object(i.b)("inlineCode",{parentName:"p"},"QuestionsBoard")," component and this example ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/callstack/react-native-testing-library/blob/main/src/__tests__/questionsBoard.test.js"}),"here"),"."))}b.isMDXComponent=!0},80:function(e,t,n){"use strict";n.d(t,"a",(function(){return p})),n.d(t,"b",(function(){return m}));var a=n(0),r=n.n(a);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function s(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=r.a.createContext({}),b=function(e){var t=r.a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):s({},t,{},e)),n},p=function(e){var t=b(e.components);return r.a.createElement(l.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},u=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,o=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),p=b(n),u=a,m=p["".concat(o,".").concat(u)]||p[u]||d[u]||i;return n?r.a.createElement(m,s({ref:t},l,{components:n})):r.a.createElement(m,s({ref:t},l))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,o=new Array(i);o[0]=u;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s.mdxType="string"==typeof e?e:a,o[1]=s;for(var l=2;l=16.9.0 (featuring async ",Object(i.b)("inlineCode",{parentName:"p"},"act"),") or React Native >=0.61 (which comes with React >=16.9.0)."))),Object(i.b)("h3",{id:"additional-jest-matchers"},"Additional Jest matchers"),Object(i.b)("p",null,"In order to use addtional React Native-specific jest matchers from ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/testing-library/jest-native"}),"@testing-library/jest-native")," package add it to your project:"),Object(i.b)("h4",{id:"using-yarn-1"},"Using ",Object(i.b)("inlineCode",{parentName:"h4"},"yarn")),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-sh"}),"yarn add --dev @testing-library/jest-native\n")),Object(i.b)("h4",{id:"using-npm-1"},"Using ",Object(i.b)("inlineCode",{parentName:"h4"},"npm")),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-sh"}),"npm install --save-dev @testing-library/jest-native\n")),Object(i.b)("p",null,"Then automatically add it to your jest tests by using ",Object(i.b)("inlineCode",{parentName:"p"},"setupFilesAfterEnv")," option in your Jest configuration (it's usually located either in ",Object(i.b)("inlineCode",{parentName:"p"},"package.json")," under ",Object(i.b)("inlineCode",{parentName:"p"},'"jest"')," key or in a ",Object(i.b)("inlineCode",{parentName:"p"},"jest.config.js")," file):"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-json"}),'{\n "preset": "react-native",\n "setupFilesAfterEnv": ["@testing-library/jest-native/extend-expect"]\n}\n')),Object(i.b)("h3",{id:"flow"},"Flow"),Object(i.b)("p",null,"Note for ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"https://flow.org"}),"Flow")," users \u2013 you'll also need to install typings for ",Object(i.b)("inlineCode",{parentName:"p"},"react-test-renderer"),":"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-sh"}),"flow-typed install react-test-renderer\n")),Object(i.b)("h2",{id:"example"},"Example"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"import { render, fireEvent } from '@testing-library/react-native';\nimport { QuestionsBoard } from '../QuestionsBoard';\n\ntest('form submits two answers', () => {\n const allQuestions = ['q1', 'q2'];\n const mockFn = jest.fn();\n\n const { getAllByLabelText, getByText } = render(\n \n );\n\n const answerInputs = getAllByLabelText('answer input');\n\n fireEvent.changeText(answerInputs[0], 'a1');\n fireEvent.changeText(answerInputs[1], 'a2');\n fireEvent.press(getByText('Submit'));\n\n expect(mockFn).toBeCalledWith({\n '1': { q: 'q1', a: 'a1' },\n '2': { q: 'q2', a: 'a2' },\n });\n});\n")),Object(i.b)("p",null,"You can find the source of ",Object(i.b)("inlineCode",{parentName:"p"},"QuestionsBoard")," component and this example ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/callstack/react-native-testing-library/blob/main/src/__tests__/questionsBoard.test.js"}),"here"),"."))}b.isMDXComponent=!0},80:function(e,t,n){"use strict";n.d(t,"a",(function(){return p})),n.d(t,"b",(function(){return m}));var a=n(0),r=n.n(a);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function s(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=r.a.createContext({}),b=function(e){var t=r.a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):s({},t,{},e)),n},p=function(e){var t=b(e.components);return r.a.createElement(l.Provider,{value:t},e.children)},d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},u=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,o=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),p=b(n),u=a,m=p["".concat(o,".").concat(u)]||p[u]||d[u]||i;return n?r.a.createElement(m,s({ref:t},l,{components:n})):r.a.createElement(m,s({ref:t},l))}));function m(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,o=new Array(i);o[0]=u;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s.mdxType="string"==typeof e?e:a,o[1]=s;for(var l=2;lrender",id:"render",children:[{value:"...queries",id:"queries",children:[]},{value:"update",id:"update",children:[]},{value:"unmount",id:"unmount",children:[]},{value:"debug",id:"debug",children:[]},{value:"toJSON",id:"tojson",children:[]},{value:"container",id:"container",children:[]}]},{value:"cleanup",id:"cleanup",children:[]},{value:"fireEvent",id:"fireevent",children:[]},{value:"fireEvent[eventName]",id:"fireeventeventname",children:[{value:"fireEvent.press: (element: ReactTestInstance, ...data: Array<any>) => void",id:"fireeventpress-element-reacttestinstance-data-arrayany--void",children:[]},{value:"fireEvent.changeText: (element: ReactTestInstance, ...data: Array<any>) => void",id:"fireeventchangetext-element-reacttestinstance-data-arrayany--void",children:[]},{value:"fireEvent.scroll: (element: ReactTestInstance, ...data: Array<any>) => void",id:"fireeventscroll-element-reacttestinstance-data-arrayany--void",children:[]}]},{value:"waitFor",id:"waitfor",children:[]},{value:"waitForElementToBeRemoved",id:"waitforelementtoberemoved",children:[]},{value:"within, getQueriesForElement",id:"within-getqueriesforelement",children:[]},{value:"query APIs",id:"query-apis",children:[]},{value:"queryAll APIs",id:"queryall-apis",children:[]},{value:"act",id:"act",children:[]}],s={rightToc:l};function b(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(i.b)("wrapper",Object(a.a)({},s,n,{components:t,mdxType:"MDXLayout"}),Object(i.b)("p",null,"This page gathers public API of React Native Testing Library along with usage examples."),Object(i.b)("h2",{id:"render"},Object(i.b)("inlineCode",{parentName:"h2"},"render")),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"https://github.com/callstack/react-native-testing-library/blob/main/src/__tests__/render.test.js"}),Object(i.b)("inlineCode",{parentName:"a"},"Example code")))),Object(i.b)("p",null,"Defined as:"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"function render(\n component: React.Element,\n options?: {\n /* A React Component that renders `component` as children */\n wrapper?: React.ComponentType,\n /* You won't often use this, but it's helpful when testing refs */\n createNodeMock: (element: React.Element) => any,\n }\n): RenderResult {}\n")),Object(i.b)("p",null,"Deeply renders given React element and returns helpers to query the output components structure."),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"import { render } from '@testing-library/react-native';\nimport { QuestionsBoard } from '../QuestionsBoard';\n\ntest('should verify two questions', () => {\n const { queryAllByA11yRole } = render();\n const allQuestions = queryAllByA11yRole('header');\n\n expect(allQuestions).toHaveLength(2);\n});\n")),Object(i.b)("blockquote",null,Object(i.b)("p",{parentName:"blockquote"},"When using React context providers, like Redux Provider, you'll likely want to wrap rendered component with them. In such cases it's convenient to create your custom ",Object(i.b)("inlineCode",{parentName:"p"},"render")," method. ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"https://testing-library.com/docs/react-testing-library/setup#custom-render"}),"Follow this great guide on how to set this up"),".")),Object(i.b)("p",null,"The ",Object(i.b)("inlineCode",{parentName:"p"},"render")," method returns a ",Object(i.b)("inlineCode",{parentName:"p"},"RenderResult")," object that has a few properties:"),Object(i.b)("h3",{id:"queries"},Object(i.b)("inlineCode",{parentName:"h3"},"...queries")),Object(i.b)("p",null,"The most important feature of ",Object(i.b)("inlineCode",{parentName:"p"},"render")," is providing a set of helpful queries that allow you to find certain elements in the view hierarchy."),Object(i.b)("p",null,"See ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/react-native-testing-library/docs/api-queries"}),"Queries")," for a complete list."),Object(i.b)("h4",{id:"example"},"Example"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"import { render } from '@testing-library/react-native';\n\nconst { getByText, queryByA11yStates } = render();\n")),Object(i.b)("h3",{id:"update"},Object(i.b)("inlineCode",{parentName:"h3"},"update")),Object(i.b)("p",null,Object(i.b)("em",{parentName:"p"},"Also available under ",Object(i.b)("inlineCode",{parentName:"em"},"rerender")," alias")),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-ts"}),"update(element: React.Element): void\nrerender(element: React.Element): void\n")),Object(i.b)("p",null,"Re-render the in-memory tree with a new root element. This simulates a React update at the root. If the new element has the same type and key as the previous element, the tree will be updated; otherwise, it will re-mount a new tree. This is useful when testing for ",Object(i.b)("inlineCode",{parentName:"p"},"componentDidUpdate")," behavior, by passing updated props to the component."),Object(i.b)("p",null,Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/callstack/react-native-testing-library/blob/f96d782d26dd4815dbfd01de6ef7a647efd1f693/src/__tests__/act.test.js#L31-L37"}),"Example code")),Object(i.b)("h3",{id:"unmount"},Object(i.b)("inlineCode",{parentName:"h3"},"unmount")),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-ts"}),"unmount(): void\n")),Object(i.b)("p",null,"Unmount the in-memory tree, triggering the appropriate lifecycle events."),Object(i.b)("div",{className:"admonition admonition-note alert alert--secondary"},Object(i.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-heading"}),Object(i.b)("h5",{parentName:"div"},Object(i.b)("span",Object(a.a)({parentName:"h5"},{className:"admonition-icon"}),Object(i.b)("svg",Object(a.a)({parentName:"span"},{xmlns:"http://www.w3.org/2000/svg",width:"14",height:"16",viewBox:"0 0 14 16"}),Object(i.b)("path",Object(a.a)({parentName:"svg"},{fillRule:"evenodd",d:"M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"})))),"note")),Object(i.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-content"}),Object(i.b)("p",{parentName:"div"},"Usually you should not need to call ",Object(i.b)("inlineCode",{parentName:"p"},"unmount")," as it is done automatically if your test runner supports ",Object(i.b)("inlineCode",{parentName:"p"},"afterEach")," hook (like Jest, mocha, Jasmine)."))),Object(i.b)("h3",{id:"debug"},Object(i.b)("inlineCode",{parentName:"h3"},"debug")),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-ts"}),"debug(message?: string): void\n")),Object(i.b)("p",null,"Pretty prints deeply rendered component passed to ",Object(i.b)("inlineCode",{parentName:"p"},"render")," with optional message on top."),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"const { debug } = render();\n\ndebug('optional message');\n")),Object(i.b)("p",null,"logs optional message and colored JSX:"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"optional message\n\n\n Press me\n\n")),Object(i.b)("h4",{id:"debugshallow"},Object(i.b)("inlineCode",{parentName:"h4"},"debug.shallow")),Object(i.b)("p",null,"Pretty prints shallowly rendered component passed to ",Object(i.b)("inlineCode",{parentName:"p"},"render")," with optional message on top."),Object(i.b)("h3",{id:"tojson"},Object(i.b)("inlineCode",{parentName:"h3"},"toJSON")),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-ts"}),"toJSON(): ReactTestRendererJSON | null\n")),Object(i.b)("p",null,"Get the rendered component JSON representation, e.g. for snapshot testing."),Object(i.b)("h3",{id:"container"},Object(i.b)("inlineCode",{parentName:"h3"},"container")),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-ts"}),"container: ReactTestInstance;\n")),Object(i.b)("p",null,"A reference to the rendered root element."),Object(i.b)("h2",{id:"cleanup"},Object(i.b)("inlineCode",{parentName:"h2"},"cleanup")),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-ts"}),"const cleanup: () => void;\n")),Object(i.b)("p",null,"Unmounts React trees that were mounted with ",Object(i.b)("inlineCode",{parentName:"p"},"render"),"."),Object(i.b)("div",{className:"admonition admonition-info alert alert--info"},Object(i.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-heading"}),Object(i.b)("h5",{parentName:"div"},Object(i.b)("span",Object(a.a)({parentName:"h5"},{className:"admonition-icon"}),Object(i.b)("svg",Object(a.a)({parentName:"span"},{xmlns:"http://www.w3.org/2000/svg",width:"14",height:"16",viewBox:"0 0 14 16"}),Object(i.b)("path",Object(a.a)({parentName:"svg"},{fillRule:"evenodd",d:"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"})))),"info")),Object(i.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-content"}),Object(i.b)("p",{parentName:"div"},"Please note that this is done automatically if the testing framework you're using supports the ",Object(i.b)("inlineCode",{parentName:"p"},"afterEach")," global (like mocha, Jest, and Jasmine). If not, you will need to do manual cleanups after each test."))),Object(i.b)("p",null,"For example, if you're using the ",Object(i.b)("inlineCode",{parentName:"p"},"jest")," testing framework, then you would need to use the ",Object(i.b)("inlineCode",{parentName:"p"},"afterEach")," hook like so:"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"import { cleanup, render } from '@testing-library/react-native/pure';\nimport { View } from 'react-native';\n\nafterEach(cleanup);\n\nit('renders a view', () => {\n render();\n // ...\n});\n")),Object(i.b)("p",null,"The ",Object(i.b)("inlineCode",{parentName:"p"},"afterEach(cleanup)")," call also works in ",Object(i.b)("inlineCode",{parentName:"p"},"describe")," blocks:"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"describe('when logged in', () => {\n afterEach(cleanup);\n\n it('renders the user', () => {\n render();\n // ...\n });\n});\n")),Object(i.b)("p",null,"Failing to call ",Object(i.b)("inlineCode",{parentName:"p"},"cleanup")," when you've called ",Object(i.b)("inlineCode",{parentName:"p"},"render"),' could result in a memory leak and tests which are not "idempotent" (which can lead to difficult to debug errors in your tests).'),Object(i.b)("p",null,"The alternative to ",Object(i.b)("inlineCode",{parentName:"p"},"cleanup")," is balancing every ",Object(i.b)("inlineCode",{parentName:"p"},"render")," with an ",Object(i.b)("inlineCode",{parentName:"p"},"unmount")," method call."),Object(i.b)("h2",{id:"fireevent"},Object(i.b)("inlineCode",{parentName:"h2"},"fireEvent")),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-ts"}),"fireEvent(element: ReactTestInstance, eventName: string, ...data: Array): void\n")),Object(i.b)("p",null,"Fires native-like event with data."),Object(i.b)("p",null,"Invokes a given event handler (whether native or custom) on the element, bubbling to the root of the rendered tree."),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"import { render, fireEvent } from '@testing-library/react-native';\n\ntest('fire changeText event', () => {\n const onEventMock = jest.fn();\n const { getByPlaceholderText } = render(\n // MyComponent renders TextInput which has a placeholder 'Enter details'\n // and with `onChangeText` bound to handleChangeText\n \n );\n\n fireEvent(getByPlaceholderText('change'), 'onChangeText', 'ab');\n expect(onEventMock).toHaveBeenCalledWith('ab');\n});\n")),Object(i.b)("div",{className:"admonition admonition-note alert alert--secondary"},Object(i.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-heading"}),Object(i.b)("h5",{parentName:"div"},Object(i.b)("span",Object(a.a)({parentName:"h5"},{className:"admonition-icon"}),Object(i.b)("svg",Object(a.a)({parentName:"span"},{xmlns:"http://www.w3.org/2000/svg",width:"14",height:"16",viewBox:"0 0 14 16"}),Object(i.b)("path",Object(a.a)({parentName:"svg"},{fillRule:"evenodd",d:"M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"})))),"note")),Object(i.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-content"}),Object(i.b)("p",{parentName:"div"},"Please note that from version ",Object(i.b)("inlineCode",{parentName:"p"},"7.0")," ",Object(i.b)("inlineCode",{parentName:"p"},"fireEvent")," performs checks that should prevent events firing on disabled elements."))),Object(i.b)("p",null,"An example using ",Object(i.b)("inlineCode",{parentName:"p"},"fireEvent")," with native events that aren't already aliased by the ",Object(i.b)("inlineCode",{parentName:"p"},"fireEvent")," api."),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"import { TextInput, View } from 'react-native';\nimport { fireEvent, render } from '@testing-library/react-native';\n\nconst onBlurMock = jest.fn();\n\nconst { getByPlaceholderText } = render(\n \n \n \n);\n\n// you can omit the `on` prefix\nfireEvent(getByPlaceholderText('my placeholder'), 'blur');\n")),Object(i.b)("h2",{id:"fireeventeventname"},Object(i.b)("inlineCode",{parentName:"h2"},"fireEvent[eventName]")),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-ts"}),"fireEvent[eventName](element: ReactTestInstance, ...data: Array): void\n")),Object(i.b)("p",null,"Convenience methods for common events like: ",Object(i.b)("inlineCode",{parentName:"p"},"press"),", ",Object(i.b)("inlineCode",{parentName:"p"},"changeText"),", ",Object(i.b)("inlineCode",{parentName:"p"},"scroll"),"."),Object(i.b)("h3",{id:"fireeventpress-element-reacttestinstance-data-arrayany--void"},Object(i.b)("inlineCode",{parentName:"h3"},"fireEvent.press: (element: ReactTestInstance, ...data: Array) => void")),Object(i.b)("p",null,"Invokes ",Object(i.b)("inlineCode",{parentName:"p"},"press")," event handler on the element or parent element in the tree."),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"import { View, Text, TouchableOpacity } from 'react-native';\nimport { render, fireEvent } from '@testing-library/react-native';\n\nconst onPressMock = jest.fn();\nconst eventData = {\n nativeEvent: {\n pageX: 20,\n pageY: 30,\n },\n};\n\nconst { getByText } = render(\n \n \n Press me\n \n \n);\n\nfireEvent.press(getByText('Press me'), eventData);\nexpect(onPressMock).toHaveBeenCalledWith(eventData);\n")),Object(i.b)("h3",{id:"fireeventchangetext-element-reacttestinstance-data-arrayany--void"},Object(i.b)("inlineCode",{parentName:"h3"},"fireEvent.changeText: (element: ReactTestInstance, ...data: Array) => void")),Object(i.b)("p",null,"Invokes ",Object(i.b)("inlineCode",{parentName:"p"},"changeText")," event handler on the element or parent element in the tree."),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"import { View, TextInput } from 'react-native';\nimport { render, fireEvent } from '@testing-library/react-native';\n\nconst onChangeTextMock = jest.fn();\nconst CHANGE_TEXT = 'content';\n\nconst { getByPlaceholderText } = render(\n \n \n \n);\n\nfireEvent.changeText(getByPlaceholderText('Enter data'), CHANGE_TEXT);\n")),Object(i.b)("h3",{id:"fireeventscroll-element-reacttestinstance-data-arrayany--void"},Object(i.b)("inlineCode",{parentName:"h3"},"fireEvent.scroll: (element: ReactTestInstance, ...data: Array) => void")),Object(i.b)("p",null,"Invokes ",Object(i.b)("inlineCode",{parentName:"p"},"scroll")," event handler on the element or parent element in the tree."),Object(i.b)("h4",{id:"on-a-scrollview"},"On a ",Object(i.b)("inlineCode",{parentName:"h4"},"ScrollView")),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"import { ScrollView, Text } from 'react-native';\nimport { render, fireEvent } from '@testing-library/react-native';\n\nconst onScrollMock = jest.fn();\nconst eventData = {\n nativeEvent: {\n contentOffset: {\n y: 200,\n },\n },\n};\n\nconst { getByText } = render(\n \n XD\n \n);\n\nfireEvent.scroll(getByText('scroll-view'), eventData);\n")),Object(i.b)("h4",{id:"on-a-flatlist"},"On a ",Object(i.b)("inlineCode",{parentName:"h4"},"FlatList")),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"import { FlatList, View } from 'react-native';\nimport { render, fireEvent } from '@testing-library/react-native';\n\nconst onEndReached = jest.fn();\nconst { getByTestId } = render(\n ({ key: `${key}` }))}\n renderItem={() => }\n onEndReached={onEndReached}\n onEndReachedThreshold={0.2}\n testID=\"flat-list\"\n />\n);\nconst eventData = {\n nativeEvent: {\n contentOffset: {\n y: 500,\n },\n contentSize: {\n // Dimensions of the scrollable content\n height: 500,\n width: 100,\n },\n layoutMeasurement: {\n // Dimensions of the device\n height: 100,\n width: 100,\n },\n },\n};\n\nfireEvent.scroll(getByTestId('flat-list'), eventData);\nexpect(onEndReached).toHaveBeenCalled();\n")),Object(i.b)("div",{className:"admonition admonition-note alert alert--secondary"},Object(i.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-heading"}),Object(i.b)("h5",{parentName:"div"},Object(i.b)("span",Object(a.a)({parentName:"h5"},{className:"admonition-icon"}),Object(i.b)("svg",Object(a.a)({parentName:"span"},{xmlns:"http://www.w3.org/2000/svg",width:"14",height:"16",viewBox:"0 0 14 16"}),Object(i.b)("path",Object(a.a)({parentName:"svg"},{fillRule:"evenodd",d:"M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"})))),"note")),Object(i.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-content"}),Object(i.b)("p",{parentName:"div"},"If you're noticing that components are not being found on a list, even after mocking a scroll event, try changing the ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"https://reactnative.dev/docs/flatlist#initialnumtorender"}),Object(i.b)("inlineCode",{parentName:"a"},"initialNumToRender"))," that you have set. If you aren't comfortable changing the code to accept this prop from the unit test, try using an e2e test that might better suit what use case you're attempting to replicate."))),Object(i.b)("h2",{id:"waitfor"},Object(i.b)("inlineCode",{parentName:"h2"},"waitFor")),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"https://github.com/callstack/react-native-testing-library/blob/main/src/__tests__/waitFor.test.js"}),Object(i.b)("inlineCode",{parentName:"a"},"Example code")))),Object(i.b)("p",null,"Defined as:"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"function waitFor(\n expectation: () => T,\n { timeout: number = 4500, interval: number = 50 }\n): Promise {}\n")),Object(i.b)("p",null,"Waits for non-deterministic periods of time until your element appears or times out. ",Object(i.b)("inlineCode",{parentName:"p"},"waitFor")," periodically calls ",Object(i.b)("inlineCode",{parentName:"p"},"expectation")," every ",Object(i.b)("inlineCode",{parentName:"p"},"interval")," milliseconds to determine whether the element appeared or not."),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"import { render, waitFor } from '@testing-library/react-native';\n\ntest('waiting for an Banana to be ready', async () => {\n const { getByText } = render();\n\n await waitFor(() => getByText('Banana ready'));\n});\n")),Object(i.b)("div",{className:"admonition admonition-info alert alert--info"},Object(i.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-heading"}),Object(i.b)("h5",{parentName:"div"},Object(i.b)("span",Object(a.a)({parentName:"h5"},{className:"admonition-icon"}),Object(i.b)("svg",Object(a.a)({parentName:"span"},{xmlns:"http://www.w3.org/2000/svg",width:"14",height:"16",viewBox:"0 0 14 16"}),Object(i.b)("path",Object(a.a)({parentName:"svg"},{fillRule:"evenodd",d:"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"})))),"info")),Object(i.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-content"}),Object(i.b)("p",{parentName:"div"},"In order to properly use ",Object(i.b)("inlineCode",{parentName:"p"},"waitFor")," you need at least React >=16.9.0 (featuring async ",Object(i.b)("inlineCode",{parentName:"p"},"act"),") or React Native >=0.61 (which comes with React >=16.9.0)."))),Object(i.b)("h2",{id:"waitforelementtoberemoved"},Object(i.b)("inlineCode",{parentName:"h2"},"waitForElementToBeRemoved")),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"https://github.com/callstack/react-native-testing-library/blob/main/src/__tests__/waitForElementToBeRemoved.test.js"}),Object(i.b)("inlineCode",{parentName:"a"},"Example code")))),Object(i.b)("p",null,"Defined as:"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"function waitForElementToBeRemoved(\n expectation: () => T,\n { timeout: number = 4500, interval: number = 50 }\n): Promise {}\n")),Object(i.b)("p",null,"Waits for non-deterministic periods of time until queried element is removed or times out. ",Object(i.b)("inlineCode",{parentName:"p"},"waitForElementToBeRemoved")," periodically calls ",Object(i.b)("inlineCode",{parentName:"p"},"expectation")," every ",Object(i.b)("inlineCode",{parentName:"p"},"interval")," milliseconds to determine whether the element has been removed or not."),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"import {\n render,\n waitForElementToBeRemoved,\n} from '@testing-library/react-native';\n\ntest('waiting for an Banana to be removed', async () => {\n const { getByText } = render();\n\n await waitForElementToBeRemoved(() => getByText('Banana ready'));\n});\n")),Object(i.b)("p",null,"This method expects that the element is initally present in the render tree and then is removed from it. If the element is not present when you call this method it throws an error."),Object(i.b)("p",null,"You can use any of ",Object(i.b)("inlineCode",{parentName:"p"},"getBy"),", ",Object(i.b)("inlineCode",{parentName:"p"},"getAllBy"),", ",Object(i.b)("inlineCode",{parentName:"p"},"queryBy")," and ",Object(i.b)("inlineCode",{parentName:"p"},"queryAllBy")," queries for ",Object(i.b)("inlineCode",{parentName:"p"},"expectation")," parameter."),Object(i.b)("div",{className:"admonition admonition-info alert alert--info"},Object(i.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-heading"}),Object(i.b)("h5",{parentName:"div"},Object(i.b)("span",Object(a.a)({parentName:"h5"},{className:"admonition-icon"}),Object(i.b)("svg",Object(a.a)({parentName:"span"},{xmlns:"http://www.w3.org/2000/svg",width:"14",height:"16",viewBox:"0 0 14 16"}),Object(i.b)("path",Object(a.a)({parentName:"svg"},{fillRule:"evenodd",d:"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"})))),"info")),Object(i.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-content"}),Object(i.b)("p",{parentName:"div"},"In order to properly use ",Object(i.b)("inlineCode",{parentName:"p"},"waitForElementToBeRemoved")," you need at least React >=16.9.0 (featuring async ",Object(i.b)("inlineCode",{parentName:"p"},"act"),") or React Native >=0.61 (which comes with React >=16.9.0)."))),Object(i.b)("h2",{id:"within-getqueriesforelement"},Object(i.b)("inlineCode",{parentName:"h2"},"within"),", ",Object(i.b)("inlineCode",{parentName:"h2"},"getQueriesForElement")),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"https://github.com/callstack/react-native-testing-library/blob/main/src/__tests__/within.test.js"}),Object(i.b)("inlineCode",{parentName:"a"},"Example code")))),Object(i.b)("p",null,"Defined as:"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"function within(instance: ReactTestInstance): Queries\nfunction getQueriesForElement(instance: ReactTestInstance): Queries\n")),Object(i.b)("p",null,Object(i.b)("inlineCode",{parentName:"p"},"within")," (also available as ",Object(i.b)("inlineCode",{parentName:"p"},"getQueriesForElement")," alias) performs ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/react-native-testing-library/docs/api-queries"}),"queries")," scoped to given element."),Object(i.b)("div",{className:"admonition admonition-note alert alert--secondary"},Object(i.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-heading"}),Object(i.b)("h5",{parentName:"div"},Object(i.b)("span",Object(a.a)({parentName:"h5"},{className:"admonition-icon"}),Object(i.b)("svg",Object(a.a)({parentName:"span"},{xmlns:"http://www.w3.org/2000/svg",width:"14",height:"16",viewBox:"0 0 14 16"}),Object(i.b)("path",Object(a.a)({parentName:"svg"},{fillRule:"evenodd",d:"M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"})))),"note")),Object(i.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-content"}),Object(i.b)("p",{parentName:"div"},"Please note that additional ",Object(i.b)("inlineCode",{parentName:"p"},"render")," specific operations like ",Object(i.b)("inlineCode",{parentName:"p"},"update"),", ",Object(i.b)("inlineCode",{parentName:"p"},"unmount"),", ",Object(i.b)("inlineCode",{parentName:"p"},"debug"),", ",Object(i.b)("inlineCode",{parentName:"p"},"toJSON")," are ",Object(i.b)("em",{parentName:"p"},"not")," included."))),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"const detailsScreen = within(getByA11yHint('Details Screen'));\nexpect(detailsScreen.getByText('Some Text')).toBeTruthy();\nexpect(detailsScreen.getByDisplayValue('Some Value')).toBeTruthy();\nexpect(detailsScreen.queryByA11yLabel('Some Label')).toBeTruthy();\nawait expect(detailsScreen.findByA11yHint('Some Label')).resolves.toBeTruthy();\n")),Object(i.b)("p",null,"Use cases for scoped queries include:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"queries scoped to a single item inside a FlatList containing many items"),Object(i.b)("li",{parentName:"ul"},"queries scoped to a single screen in tests involving screen transitions (e.g. with react-navigation)")),Object(i.b)("h2",{id:"query-apis"},Object(i.b)("inlineCode",{parentName:"h2"},"query")," APIs"),Object(i.b)("p",null,"Each of the get APIs listed in the render section above have a complimentary query API. The get APIs will throw errors if a proper node cannot be found. This is normally the desired effect. However, if you want to make an assertion that an element is not present in the hierarchy, then you can use the query API instead:"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"import { render } from '@testing-library/react-native';\n\nconst { queryByText } = render(
);\nconst submitButton = queryByText('submit');\nexpect(submitButton).toBeNull(); // it doesn't exist\n")),Object(i.b)("h2",{id:"queryall-apis"},Object(i.b)("inlineCode",{parentName:"h2"},"queryAll")," APIs"),Object(i.b)("p",null,"Each of the query APIs have a corresponding queryAll version that always returns an Array of matching nodes. getAll is the same but throws when the array has a length of 0."),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"import { render } from '@testing-library/react-native';\n\nconst { queryAllByText } = render();\nconst submitButtons = queryAllByText('submit');\nexpect(submitButtons).toHaveLength(3); // expect 3 elements\n")),Object(i.b)("h2",{id:"act"},Object(i.b)("inlineCode",{parentName:"h2"},"act")),Object(i.b)("p",null,"Useful function to help testing components that use hooks API. By default any ",Object(i.b)("inlineCode",{parentName:"p"},"render"),", ",Object(i.b)("inlineCode",{parentName:"p"},"update"),", ",Object(i.b)("inlineCode",{parentName:"p"},"fireEvent"),", and ",Object(i.b)("inlineCode",{parentName:"p"},"waitFor")," calls are wrapped by this function, so there is no need to wrap it manually. This method is re-exported from ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/facebook/react/blob/main/packages/react-test-renderer/src/ReactTestRenderer.js#L567%5D"}),Object(i.b)("inlineCode",{parentName:"a"},"react-test-renderer")),"."))}b.isMDXComponent=!0},80:function(e,t,n){"use strict";n.d(t,"a",(function(){return d})),n.d(t,"b",(function(){return u}));var a=n(0),r=n.n(a);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function c(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=r.a.createContext({}),b=function(e){var t=r.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o({},t,{},e)),n},d=function(e){var t=b(e.components);return r.a.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},m=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,c=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),d=b(n),m=a,u=d["".concat(c,".").concat(m)]||d[m]||p[m]||i;return n?r.a.createElement(u,o({ref:t},s,{components:n})):r.a.createElement(u,o({ref:t},s))}));function u(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,c=new Array(i);c[0]=m;var o={};for(var l in t)hasOwnProperty.call(t,l)&&(o[l]=t[l]);o.originalType=e,o.mdxType="string"==typeof e?e:a,c[1]=o;for(var s=2;srender",id:"render",children:[{value:"...queries",id:"queries",children:[]},{value:"update",id:"update",children:[]},{value:"unmount",id:"unmount",children:[]},{value:"debug",id:"debug",children:[]},{value:"toJSON",id:"tojson",children:[]},{value:"container",id:"container",children:[]}]},{value:"cleanup",id:"cleanup",children:[]},{value:"fireEvent",id:"fireevent",children:[]},{value:"fireEvent[eventName]",id:"fireeventeventname",children:[{value:"fireEvent.press: (element: ReactTestInstance, ...data: Array<any>) => void",id:"fireeventpress-element-reacttestinstance-data-arrayany--void",children:[]},{value:"fireEvent.changeText: (element: ReactTestInstance, ...data: Array<any>) => void",id:"fireeventchangetext-element-reacttestinstance-data-arrayany--void",children:[]},{value:"fireEvent.scroll: (element: ReactTestInstance, ...data: Array<any>) => void",id:"fireeventscroll-element-reacttestinstance-data-arrayany--void",children:[]}]},{value:"waitFor",id:"waitfor",children:[]},{value:"waitForElementToBeRemoved",id:"waitforelementtoberemoved",children:[]},{value:"within, getQueriesForElement",id:"within-getqueriesforelement",children:[]},{value:"query APIs",id:"query-apis",children:[]},{value:"queryAll APIs",id:"queryall-apis",children:[]},{value:"act",id:"act",children:[]}],s={rightToc:l};function b(e){var t=e.components,n=Object(r.a)(e,["components"]);return Object(i.b)("wrapper",Object(a.a)({},s,n,{components:t,mdxType:"MDXLayout"}),Object(i.b)("p",null,"This page gathers public API of React Native Testing Library along with usage examples."),Object(i.b)("h2",{id:"render"},Object(i.b)("inlineCode",{parentName:"h2"},"render")),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"https://github.com/callstack/react-native-testing-library/blob/main/src/__tests__/render.test.js"}),Object(i.b)("inlineCode",{parentName:"a"},"Example code")))),Object(i.b)("p",null,"Defined as:"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"function render(\n component: React.Element,\n options?: {\n /* A React Component that renders `component` as children */\n wrapper?: React.ComponentType,\n /* You won't often use this, but it's helpful when testing refs */\n createNodeMock: (element: React.Element) => any,\n }\n): RenderResult {}\n")),Object(i.b)("p",null,"Deeply renders given React element and returns helpers to query the output components structure."),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"import { render } from '@testing-library/react-native';\nimport { QuestionsBoard } from '../QuestionsBoard';\n\ntest('should verify two questions', () => {\n const { queryAllByRole } = render();\n const allQuestions = queryAllByRole('header');\n\n expect(allQuestions).toHaveLength(2);\n});\n")),Object(i.b)("blockquote",null,Object(i.b)("p",{parentName:"blockquote"},"When using React context providers, like Redux Provider, you'll likely want to wrap rendered component with them. In such cases it's convenient to create your custom ",Object(i.b)("inlineCode",{parentName:"p"},"render")," method. ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"https://testing-library.com/docs/react-testing-library/setup#custom-render"}),"Follow this great guide on how to set this up"),".")),Object(i.b)("p",null,"The ",Object(i.b)("inlineCode",{parentName:"p"},"render")," method returns a ",Object(i.b)("inlineCode",{parentName:"p"},"RenderResult")," object that has a few properties:"),Object(i.b)("h3",{id:"queries"},Object(i.b)("inlineCode",{parentName:"h3"},"...queries")),Object(i.b)("p",null,"The most important feature of ",Object(i.b)("inlineCode",{parentName:"p"},"render")," is providing a set of helpful queries that allow you to find certain elements in the view hierarchy."),Object(i.b)("p",null,"See ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/react-native-testing-library/docs/api-queries"}),"Queries")," for a complete list."),Object(i.b)("h4",{id:"example"},"Example"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"import { render } from '@testing-library/react-native';\n\nconst { getByText, queryByA11yStates } = render();\n")),Object(i.b)("h3",{id:"update"},Object(i.b)("inlineCode",{parentName:"h3"},"update")),Object(i.b)("p",null,Object(i.b)("em",{parentName:"p"},"Also available under ",Object(i.b)("inlineCode",{parentName:"em"},"rerender")," alias")),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-ts"}),"update(element: React.Element): void\nrerender(element: React.Element): void\n")),Object(i.b)("p",null,"Re-render the in-memory tree with a new root element. This simulates a React update at the root. If the new element has the same type and key as the previous element, the tree will be updated; otherwise, it will re-mount a new tree. This is useful when testing for ",Object(i.b)("inlineCode",{parentName:"p"},"componentDidUpdate")," behavior, by passing updated props to the component."),Object(i.b)("p",null,Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/callstack/react-native-testing-library/blob/f96d782d26dd4815dbfd01de6ef7a647efd1f693/src/__tests__/act.test.js#L31-L37"}),"Example code")),Object(i.b)("h3",{id:"unmount"},Object(i.b)("inlineCode",{parentName:"h3"},"unmount")),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-ts"}),"unmount(): void\n")),Object(i.b)("p",null,"Unmount the in-memory tree, triggering the appropriate lifecycle events."),Object(i.b)("div",{className:"admonition admonition-note alert alert--secondary"},Object(i.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-heading"}),Object(i.b)("h5",{parentName:"div"},Object(i.b)("span",Object(a.a)({parentName:"h5"},{className:"admonition-icon"}),Object(i.b)("svg",Object(a.a)({parentName:"span"},{xmlns:"http://www.w3.org/2000/svg",width:"14",height:"16",viewBox:"0 0 14 16"}),Object(i.b)("path",Object(a.a)({parentName:"svg"},{fillRule:"evenodd",d:"M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"})))),"note")),Object(i.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-content"}),Object(i.b)("p",{parentName:"div"},"Usually you should not need to call ",Object(i.b)("inlineCode",{parentName:"p"},"unmount")," as it is done automatically if your test runner supports ",Object(i.b)("inlineCode",{parentName:"p"},"afterEach")," hook (like Jest, mocha, Jasmine)."))),Object(i.b)("h3",{id:"debug"},Object(i.b)("inlineCode",{parentName:"h3"},"debug")),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-ts"}),"debug(message?: string): void\n")),Object(i.b)("p",null,"Pretty prints deeply rendered component passed to ",Object(i.b)("inlineCode",{parentName:"p"},"render")," with optional message on top."),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"const { debug } = render();\n\ndebug('optional message');\n")),Object(i.b)("p",null,"logs optional message and colored JSX:"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"optional message\n\n\n Press me\n\n")),Object(i.b)("h4",{id:"debugshallow"},Object(i.b)("inlineCode",{parentName:"h4"},"debug.shallow")),Object(i.b)("p",null,"Pretty prints shallowly rendered component passed to ",Object(i.b)("inlineCode",{parentName:"p"},"render")," with optional message on top."),Object(i.b)("h3",{id:"tojson"},Object(i.b)("inlineCode",{parentName:"h3"},"toJSON")),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-ts"}),"toJSON(): ReactTestRendererJSON | null\n")),Object(i.b)("p",null,"Get the rendered component JSON representation, e.g. for snapshot testing."),Object(i.b)("h3",{id:"container"},Object(i.b)("inlineCode",{parentName:"h3"},"container")),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-ts"}),"container: ReactTestInstance;\n")),Object(i.b)("p",null,"A reference to the rendered root element."),Object(i.b)("h2",{id:"cleanup"},Object(i.b)("inlineCode",{parentName:"h2"},"cleanup")),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-ts"}),"const cleanup: () => void;\n")),Object(i.b)("p",null,"Unmounts React trees that were mounted with ",Object(i.b)("inlineCode",{parentName:"p"},"render"),"."),Object(i.b)("div",{className:"admonition admonition-info alert alert--info"},Object(i.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-heading"}),Object(i.b)("h5",{parentName:"div"},Object(i.b)("span",Object(a.a)({parentName:"h5"},{className:"admonition-icon"}),Object(i.b)("svg",Object(a.a)({parentName:"span"},{xmlns:"http://www.w3.org/2000/svg",width:"14",height:"16",viewBox:"0 0 14 16"}),Object(i.b)("path",Object(a.a)({parentName:"svg"},{fillRule:"evenodd",d:"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"})))),"info")),Object(i.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-content"}),Object(i.b)("p",{parentName:"div"},"Please note that this is done automatically if the testing framework you're using supports the ",Object(i.b)("inlineCode",{parentName:"p"},"afterEach")," global (like mocha, Jest, and Jasmine). If not, you will need to do manual cleanups after each test."))),Object(i.b)("p",null,"For example, if you're using the ",Object(i.b)("inlineCode",{parentName:"p"},"jest")," testing framework, then you would need to use the ",Object(i.b)("inlineCode",{parentName:"p"},"afterEach")," hook like so:"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"import { cleanup, render } from '@testing-library/react-native/pure';\nimport { View } from 'react-native';\n\nafterEach(cleanup);\n\nit('renders a view', () => {\n render();\n // ...\n});\n")),Object(i.b)("p",null,"The ",Object(i.b)("inlineCode",{parentName:"p"},"afterEach(cleanup)")," call also works in ",Object(i.b)("inlineCode",{parentName:"p"},"describe")," blocks:"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"describe('when logged in', () => {\n afterEach(cleanup);\n\n it('renders the user', () => {\n render();\n // ...\n });\n});\n")),Object(i.b)("p",null,"Failing to call ",Object(i.b)("inlineCode",{parentName:"p"},"cleanup")," when you've called ",Object(i.b)("inlineCode",{parentName:"p"},"render"),' could result in a memory leak and tests which are not "idempotent" (which can lead to difficult to debug errors in your tests).'),Object(i.b)("p",null,"The alternative to ",Object(i.b)("inlineCode",{parentName:"p"},"cleanup")," is balancing every ",Object(i.b)("inlineCode",{parentName:"p"},"render")," with an ",Object(i.b)("inlineCode",{parentName:"p"},"unmount")," method call."),Object(i.b)("h2",{id:"fireevent"},Object(i.b)("inlineCode",{parentName:"h2"},"fireEvent")),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-ts"}),"fireEvent(element: ReactTestInstance, eventName: string, ...data: Array): void\n")),Object(i.b)("p",null,"Fires native-like event with data."),Object(i.b)("p",null,"Invokes a given event handler (whether native or custom) on the element, bubbling to the root of the rendered tree."),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"import { render, fireEvent } from '@testing-library/react-native';\n\ntest('fire changeText event', () => {\n const onEventMock = jest.fn();\n const { getByPlaceholderText } = render(\n // MyComponent renders TextInput which has a placeholder 'Enter details'\n // and with `onChangeText` bound to handleChangeText\n \n );\n\n fireEvent(getByPlaceholderText('change'), 'onChangeText', 'ab');\n expect(onEventMock).toHaveBeenCalledWith('ab');\n});\n")),Object(i.b)("div",{className:"admonition admonition-note alert alert--secondary"},Object(i.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-heading"}),Object(i.b)("h5",{parentName:"div"},Object(i.b)("span",Object(a.a)({parentName:"h5"},{className:"admonition-icon"}),Object(i.b)("svg",Object(a.a)({parentName:"span"},{xmlns:"http://www.w3.org/2000/svg",width:"14",height:"16",viewBox:"0 0 14 16"}),Object(i.b)("path",Object(a.a)({parentName:"svg"},{fillRule:"evenodd",d:"M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"})))),"note")),Object(i.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-content"}),Object(i.b)("p",{parentName:"div"},"Please note that from version ",Object(i.b)("inlineCode",{parentName:"p"},"7.0")," ",Object(i.b)("inlineCode",{parentName:"p"},"fireEvent")," performs checks that should prevent events firing on disabled elements."))),Object(i.b)("p",null,"An example using ",Object(i.b)("inlineCode",{parentName:"p"},"fireEvent")," with native events that aren't already aliased by the ",Object(i.b)("inlineCode",{parentName:"p"},"fireEvent")," api."),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"import { TextInput, View } from 'react-native';\nimport { fireEvent, render } from '@testing-library/react-native';\n\nconst onBlurMock = jest.fn();\n\nconst { getByPlaceholderText } = render(\n \n \n \n);\n\n// you can omit the `on` prefix\nfireEvent(getByPlaceholderText('my placeholder'), 'blur');\n")),Object(i.b)("h2",{id:"fireeventeventname"},Object(i.b)("inlineCode",{parentName:"h2"},"fireEvent[eventName]")),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-ts"}),"fireEvent[eventName](element: ReactTestInstance, ...data: Array): void\n")),Object(i.b)("p",null,"Convenience methods for common events like: ",Object(i.b)("inlineCode",{parentName:"p"},"press"),", ",Object(i.b)("inlineCode",{parentName:"p"},"changeText"),", ",Object(i.b)("inlineCode",{parentName:"p"},"scroll"),"."),Object(i.b)("h3",{id:"fireeventpress-element-reacttestinstance-data-arrayany--void"},Object(i.b)("inlineCode",{parentName:"h3"},"fireEvent.press: (element: ReactTestInstance, ...data: Array) => void")),Object(i.b)("p",null,"Invokes ",Object(i.b)("inlineCode",{parentName:"p"},"press")," event handler on the element or parent element in the tree."),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"import { View, Text, TouchableOpacity } from 'react-native';\nimport { render, fireEvent } from '@testing-library/react-native';\n\nconst onPressMock = jest.fn();\nconst eventData = {\n nativeEvent: {\n pageX: 20,\n pageY: 30,\n },\n};\n\nconst { getByText } = render(\n \n \n Press me\n \n \n);\n\nfireEvent.press(getByText('Press me'), eventData);\nexpect(onPressMock).toHaveBeenCalledWith(eventData);\n")),Object(i.b)("h3",{id:"fireeventchangetext-element-reacttestinstance-data-arrayany--void"},Object(i.b)("inlineCode",{parentName:"h3"},"fireEvent.changeText: (element: ReactTestInstance, ...data: Array) => void")),Object(i.b)("p",null,"Invokes ",Object(i.b)("inlineCode",{parentName:"p"},"changeText")," event handler on the element or parent element in the tree."),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"import { View, TextInput } from 'react-native';\nimport { render, fireEvent } from '@testing-library/react-native';\n\nconst onChangeTextMock = jest.fn();\nconst CHANGE_TEXT = 'content';\n\nconst { getByPlaceholderText } = render(\n \n \n \n);\n\nfireEvent.changeText(getByPlaceholderText('Enter data'), CHANGE_TEXT);\n")),Object(i.b)("h3",{id:"fireeventscroll-element-reacttestinstance-data-arrayany--void"},Object(i.b)("inlineCode",{parentName:"h3"},"fireEvent.scroll: (element: ReactTestInstance, ...data: Array) => void")),Object(i.b)("p",null,"Invokes ",Object(i.b)("inlineCode",{parentName:"p"},"scroll")," event handler on the element or parent element in the tree."),Object(i.b)("h4",{id:"on-a-scrollview"},"On a ",Object(i.b)("inlineCode",{parentName:"h4"},"ScrollView")),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"import { ScrollView, Text } from 'react-native';\nimport { render, fireEvent } from '@testing-library/react-native';\n\nconst onScrollMock = jest.fn();\nconst eventData = {\n nativeEvent: {\n contentOffset: {\n y: 200,\n },\n },\n};\n\nconst { getByText } = render(\n \n XD\n \n);\n\nfireEvent.scroll(getByText('scroll-view'), eventData);\n")),Object(i.b)("h4",{id:"on-a-flatlist"},"On a ",Object(i.b)("inlineCode",{parentName:"h4"},"FlatList")),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"import { FlatList, View } from 'react-native';\nimport { render, fireEvent } from '@testing-library/react-native';\n\nconst onEndReached = jest.fn();\nconst { getByTestId } = render(\n ({ key: `${key}` }))}\n renderItem={() => }\n onEndReached={onEndReached}\n onEndReachedThreshold={0.2}\n testID=\"flat-list\"\n />\n);\nconst eventData = {\n nativeEvent: {\n contentOffset: {\n y: 500,\n },\n contentSize: {\n // Dimensions of the scrollable content\n height: 500,\n width: 100,\n },\n layoutMeasurement: {\n // Dimensions of the device\n height: 100,\n width: 100,\n },\n },\n};\n\nfireEvent.scroll(getByTestId('flat-list'), eventData);\nexpect(onEndReached).toHaveBeenCalled();\n")),Object(i.b)("div",{className:"admonition admonition-note alert alert--secondary"},Object(i.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-heading"}),Object(i.b)("h5",{parentName:"div"},Object(i.b)("span",Object(a.a)({parentName:"h5"},{className:"admonition-icon"}),Object(i.b)("svg",Object(a.a)({parentName:"span"},{xmlns:"http://www.w3.org/2000/svg",width:"14",height:"16",viewBox:"0 0 14 16"}),Object(i.b)("path",Object(a.a)({parentName:"svg"},{fillRule:"evenodd",d:"M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"})))),"note")),Object(i.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-content"}),Object(i.b)("p",{parentName:"div"},"If you're noticing that components are not being found on a list, even after mocking a scroll event, try changing the ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"https://reactnative.dev/docs/flatlist#initialnumtorender"}),Object(i.b)("inlineCode",{parentName:"a"},"initialNumToRender"))," that you have set. If you aren't comfortable changing the code to accept this prop from the unit test, try using an e2e test that might better suit what use case you're attempting to replicate."))),Object(i.b)("h2",{id:"waitfor"},Object(i.b)("inlineCode",{parentName:"h2"},"waitFor")),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"https://github.com/callstack/react-native-testing-library/blob/main/src/__tests__/waitFor.test.js"}),Object(i.b)("inlineCode",{parentName:"a"},"Example code")))),Object(i.b)("p",null,"Defined as:"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"function waitFor(\n expectation: () => T,\n { timeout: number = 4500, interval: number = 50 }\n): Promise {}\n")),Object(i.b)("p",null,"Waits for non-deterministic periods of time until your element appears or times out. ",Object(i.b)("inlineCode",{parentName:"p"},"waitFor")," periodically calls ",Object(i.b)("inlineCode",{parentName:"p"},"expectation")," every ",Object(i.b)("inlineCode",{parentName:"p"},"interval")," milliseconds to determine whether the element appeared or not."),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"import { render, waitFor } from '@testing-library/react-native';\n\ntest('waiting for an Banana to be ready', async () => {\n const { getByText } = render();\n\n await waitFor(() => getByText('Banana ready'));\n});\n")),Object(i.b)("div",{className:"admonition admonition-info alert alert--info"},Object(i.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-heading"}),Object(i.b)("h5",{parentName:"div"},Object(i.b)("span",Object(a.a)({parentName:"h5"},{className:"admonition-icon"}),Object(i.b)("svg",Object(a.a)({parentName:"span"},{xmlns:"http://www.w3.org/2000/svg",width:"14",height:"16",viewBox:"0 0 14 16"}),Object(i.b)("path",Object(a.a)({parentName:"svg"},{fillRule:"evenodd",d:"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"})))),"info")),Object(i.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-content"}),Object(i.b)("p",{parentName:"div"},"In order to properly use ",Object(i.b)("inlineCode",{parentName:"p"},"waitFor")," you need at least React >=16.9.0 (featuring async ",Object(i.b)("inlineCode",{parentName:"p"},"act"),") or React Native >=0.61 (which comes with React >=16.9.0)."))),Object(i.b)("h2",{id:"waitforelementtoberemoved"},Object(i.b)("inlineCode",{parentName:"h2"},"waitForElementToBeRemoved")),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"https://github.com/callstack/react-native-testing-library/blob/main/src/__tests__/waitForElementToBeRemoved.test.js"}),Object(i.b)("inlineCode",{parentName:"a"},"Example code")))),Object(i.b)("p",null,"Defined as:"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"function waitForElementToBeRemoved(\n expectation: () => T,\n { timeout: number = 4500, interval: number = 50 }\n): Promise {}\n")),Object(i.b)("p",null,"Waits for non-deterministic periods of time until queried element is removed or times out. ",Object(i.b)("inlineCode",{parentName:"p"},"waitForElementToBeRemoved")," periodically calls ",Object(i.b)("inlineCode",{parentName:"p"},"expectation")," every ",Object(i.b)("inlineCode",{parentName:"p"},"interval")," milliseconds to determine whether the element has been removed or not."),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"import {\n render,\n waitForElementToBeRemoved,\n} from '@testing-library/react-native';\n\ntest('waiting for an Banana to be removed', async () => {\n const { getByText } = render();\n\n await waitForElementToBeRemoved(() => getByText('Banana ready'));\n});\n")),Object(i.b)("p",null,"This method expects that the element is initally present in the render tree and then is removed from it. If the element is not present when you call this method it throws an error."),Object(i.b)("p",null,"You can use any of ",Object(i.b)("inlineCode",{parentName:"p"},"getBy"),", ",Object(i.b)("inlineCode",{parentName:"p"},"getAllBy"),", ",Object(i.b)("inlineCode",{parentName:"p"},"queryBy")," and ",Object(i.b)("inlineCode",{parentName:"p"},"queryAllBy")," queries for ",Object(i.b)("inlineCode",{parentName:"p"},"expectation")," parameter."),Object(i.b)("div",{className:"admonition admonition-info alert alert--info"},Object(i.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-heading"}),Object(i.b)("h5",{parentName:"div"},Object(i.b)("span",Object(a.a)({parentName:"h5"},{className:"admonition-icon"}),Object(i.b)("svg",Object(a.a)({parentName:"span"},{xmlns:"http://www.w3.org/2000/svg",width:"14",height:"16",viewBox:"0 0 14 16"}),Object(i.b)("path",Object(a.a)({parentName:"svg"},{fillRule:"evenodd",d:"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"})))),"info")),Object(i.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-content"}),Object(i.b)("p",{parentName:"div"},"In order to properly use ",Object(i.b)("inlineCode",{parentName:"p"},"waitForElementToBeRemoved")," you need at least React >=16.9.0 (featuring async ",Object(i.b)("inlineCode",{parentName:"p"},"act"),") or React Native >=0.61 (which comes with React >=16.9.0)."))),Object(i.b)("h2",{id:"within-getqueriesforelement"},Object(i.b)("inlineCode",{parentName:"h2"},"within"),", ",Object(i.b)("inlineCode",{parentName:"h2"},"getQueriesForElement")),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},Object(i.b)("a",Object(a.a)({parentName:"li"},{href:"https://github.com/callstack/react-native-testing-library/blob/main/src/__tests__/within.test.js"}),Object(i.b)("inlineCode",{parentName:"a"},"Example code")))),Object(i.b)("p",null,"Defined as:"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"function within(instance: ReactTestInstance): Queries\nfunction getQueriesForElement(instance: ReactTestInstance): Queries\n")),Object(i.b)("p",null,Object(i.b)("inlineCode",{parentName:"p"},"within")," (also available as ",Object(i.b)("inlineCode",{parentName:"p"},"getQueriesForElement")," alias) performs ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"/react-native-testing-library/docs/api-queries"}),"queries")," scoped to given element."),Object(i.b)("div",{className:"admonition admonition-note alert alert--secondary"},Object(i.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-heading"}),Object(i.b)("h5",{parentName:"div"},Object(i.b)("span",Object(a.a)({parentName:"h5"},{className:"admonition-icon"}),Object(i.b)("svg",Object(a.a)({parentName:"span"},{xmlns:"http://www.w3.org/2000/svg",width:"14",height:"16",viewBox:"0 0 14 16"}),Object(i.b)("path",Object(a.a)({parentName:"svg"},{fillRule:"evenodd",d:"M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"})))),"note")),Object(i.b)("div",Object(a.a)({parentName:"div"},{className:"admonition-content"}),Object(i.b)("p",{parentName:"div"},"Please note that additional ",Object(i.b)("inlineCode",{parentName:"p"},"render")," specific operations like ",Object(i.b)("inlineCode",{parentName:"p"},"update"),", ",Object(i.b)("inlineCode",{parentName:"p"},"unmount"),", ",Object(i.b)("inlineCode",{parentName:"p"},"debug"),", ",Object(i.b)("inlineCode",{parentName:"p"},"toJSON")," are ",Object(i.b)("em",{parentName:"p"},"not")," included."))),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"const detailsScreen = within(getByA11yHint('Details Screen'));\nexpect(detailsScreen.getByText('Some Text')).toBeTruthy();\nexpect(detailsScreen.getByDisplayValue('Some Value')).toBeTruthy();\nexpect(detailsScreen.queryByLabelText('Some Label')).toBeTruthy();\nawait expect(detailsScreen.findByA11yHint('Some Label')).resolves.toBeTruthy();\n")),Object(i.b)("p",null,"Use cases for scoped queries include:"),Object(i.b)("ul",null,Object(i.b)("li",{parentName:"ul"},"queries scoped to a single item inside a FlatList containing many items"),Object(i.b)("li",{parentName:"ul"},"queries scoped to a single screen in tests involving screen transitions (e.g. with react-navigation)")),Object(i.b)("h2",{id:"query-apis"},Object(i.b)("inlineCode",{parentName:"h2"},"query")," APIs"),Object(i.b)("p",null,"Each of the get APIs listed in the render section above have a complimentary query API. The get APIs will throw errors if a proper node cannot be found. This is normally the desired effect. However, if you want to make an assertion that an element is not present in the hierarchy, then you can use the query API instead:"),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"import { render } from '@testing-library/react-native';\n\nconst { queryByText } = render();\nconst submitButton = queryByText('submit');\nexpect(submitButton).toBeNull(); // it doesn't exist\n")),Object(i.b)("h2",{id:"queryall-apis"},Object(i.b)("inlineCode",{parentName:"h2"},"queryAll")," APIs"),Object(i.b)("p",null,"Each of the query APIs have a corresponding queryAll version that always returns an Array of matching nodes. getAll is the same but throws when the array has a length of 0."),Object(i.b)("pre",null,Object(i.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"import { render } from '@testing-library/react-native';\n\nconst { queryAllByText } = render();\nconst submitButtons = queryAllByText('submit');\nexpect(submitButtons).toHaveLength(3); // expect 3 elements\n")),Object(i.b)("h2",{id:"act"},Object(i.b)("inlineCode",{parentName:"h2"},"act")),Object(i.b)("p",null,"Useful function to help testing components that use hooks API. By default any ",Object(i.b)("inlineCode",{parentName:"p"},"render"),", ",Object(i.b)("inlineCode",{parentName:"p"},"update"),", ",Object(i.b)("inlineCode",{parentName:"p"},"fireEvent"),", and ",Object(i.b)("inlineCode",{parentName:"p"},"waitFor")," calls are wrapped by this function, so there is no need to wrap it manually. This method is re-exported from ",Object(i.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/facebook/react/blob/main/packages/react-test-renderer/src/ReactTestRenderer.js#L567%5D"}),Object(i.b)("inlineCode",{parentName:"a"},"react-test-renderer")),"."))}b.isMDXComponent=!0},80:function(e,t,n){"use strict";n.d(t,"a",(function(){return d})),n.d(t,"b",(function(){return u}));var a=n(0),r=n.n(a);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function c(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=r.a.createContext({}),b=function(e){var t=r.a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o({},t,{},e)),n},d=function(e){var t=b(e.components);return r.a.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},m=Object(a.forwardRef)((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,c=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),d=b(n),m=a,u=d["".concat(c,".").concat(m)]||d[m]||p[m]||i;return n?r.a.createElement(u,o({ref:t},s,{components:n})):r.a.createElement(u,o({ref:t},s))}));function u(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,c=new Array(i);c[0]=m;var o={};for(var l in t)hasOwnProperty.call(t,l)&&(o[l]=t[l]);o.originalType=e,o.mdxType="string"==typeof e?e:a,c[1]=o;for(var s=2;s Queries | React Native Testing Library - + @@ -14,7 +14,7 @@ - +

ByPlaceholderText

getByPlaceholderText, getAllByPlaceholderText, queryByPlaceholderText, queryAllByPlaceholderText, findByPlaceholderText, findAllByPlaceholderText

Returns a ReactTestInstance for a TextInput with a matching placeholder โ€“ may be a string or regular expression.

import { render } from '@testing-library/react-native';
const { getByPlaceholderText } = render(<MyComponent />);
const element = getByPlaceholderText('username');

ByDisplayValue

getByDisplayValue, getAllByDisplayValue, queryByDisplayValue, queryAllByDisplayValue, findByDisplayValue, findAllByDisplayValue

Returns a ReactTestInstance for a TextInput with a matching display value โ€“ may be a string or regular expression.

import { render } from '@testing-library/react-native';
const { getByDisplayValue } = render(<MyComponent />);
const element = getByDisplayValue('username');

ByTestId

getByTestId, getAllByTestId, queryByTestId, queryAllByTestId, findByTestId, findAllByTestId

Returns a ReactTestInstance with matching testID prop. testID โ€“ may be a string or a regular expression.

import { render } from '@testing-library/react-native';
-
const { getByTestId } = render(<MyComponent />);
const element = getByTestId('unique-id');
info

In the spirit of the guiding principles, it is recommended to use this only after the other queries don't work for your use case. Using testID attributes do not resemble how your software is used and should be avoided if possible. However, they are particularly useful for end-to-end testing on real devices, e.g. using Detox and it's an encouraged technique to use there. Learn more from the blog post "Making your UI tests resilient to change".

ByA11yLabel, ByAccessibilityLabel, ByLabelText

getByA11yLabel, getAllByA11yLabel, queryByA11yLabel, queryAllByA11yLabel, findByA11yLabel, findAllByA11yLabel -getByAccessibilityLabel, getAllByAccessibilityLabel, queryByAccessibilityLabel, queryAllByAccessibilityLabel, findByAccessibilityLabel, findAllByAccessibilityLabel -getByLabelText, getAllByLabelText, queryByLabelText, queryAllByLabelText, findByLabelText, findAllByLabelText

Returns a ReactTestInstance with matching accessibilityLabel prop.

import { render } from '@testing-library/react-native';
+
const { getByTestId } = render(<MyComponent />);
const element = getByTestId('unique-id');
info

In the spirit of the guiding principles, it is recommended to use this only after the other queries don't work for your use case. Using testID attributes do not resemble how your software is used and should be avoided if possible. However, they are particularly useful for end-to-end testing on real devices, e.g. using Detox and it's an encouraged technique to use there. Learn more from the blog post "Making your UI tests resilient to change".

ByLabelText

getByLabelText, getAllByLabelText, queryByLabelText, queryAllByLabelText, findByLabelText, findAllByLabelText

Returns a ReactTestInstance with matching accessibilityLabel prop.

import { render } from '@testing-library/react-native';
const { getByLabelText } = render(<MyComponent />);
const element = getByLabelText('my-label');

ByA11yHint, ByAccessibilityHint, ByHintText

getByA11yHint, getAllByA11yHint, queryByA11yHint, queryAllByA11yHint, findByA11yHint, findAllByA11yHint getByAccessibilityHint, getAllByAccessibilityHint, queryByAccessibilityHint, queryAllByAccessibilityHint, findByAccessibilityHint, findAllByAccessibilityHint getByHintText, getAllByHintText, queryByHintText, queryAllByHintText, findByHintText, findAllByHintText

Returns a ReactTestInstance with matching accessibilityHint prop.

import { render } from '@testing-library/react-native';
const { getByHintText } = render(<MyComponent />);
const element = getByHintText('Plays a song');

ByA11yStates, ByAccessibilityStates

getByA11yStates, getAllByA11yStates, queryByA11yStates, queryAllByA11yStates getByAccessibilityStates, getAllByAccessibilityStates, queryByAccessibilityStates, queryAllByAccessibilityStates

Returns a ReactTestInstance with matching accessibilityStates prop.

import { render } from '@testing-library/react-native';
-
const { getByA11yStates } = render(<MyComponent />);
const element = getByA11yStates(['checked']);
const element2 = getByA11yStates('checked');

ByA11yRole, ByAccessibilityRole, ByRole

getByA11yRole, getAllByA11yRole, queryByA11yRole, queryAllByA11yRole, findByA11yRole, findAllByA11yRole -getByAccessibilityRole, getAllByAccessibilityRole, queryByAccessibilityRole, queryAllByAccessibilityRole, findByAccessibilityRole, findAllByAccessibilityRole -getByRole, getAllByRole, queryByRole, queryAllByRole, findByRole, findAllByRole

Returns a ReactTestInstance with matching accessibilityRole prop.

import { render } from '@testing-library/react-native';
-
const { getByA11yRole } = render(<MyComponent />);
const element = getByA11yRole('button');

ByA11yState, ByAccessibilityState

getByA11yState, getAllByA11yState, queryByA11yState, queryAllByA11yState, findByA11yState, findAllByA11yState +

const { getByA11yStates } = render(<MyComponent />);
const element = getByA11yStates(['checked']);
const element2 = getByA11yStates('checked');

ByRole

getByRole, getAllByRole, queryByRole, queryAllByRole, findByRole, findAllByRole

Returns a ReactTestInstance with matching accessibilityRole prop.

import { render } from '@testing-library/react-native';
+
const { getByRole } = render(<MyComponent />);
const element = getByRole('button');

ByA11yState, ByAccessibilityState

getByA11yState, getAllByA11yState, queryByA11yState, queryAllByA11yState, findByA11yState, findAllByA11yState getByAccessibilityState, getAllByAccessibilityState, queryByAccessibilityState, queryAllByAccessibilityState, findByAccessibilityState, findAllByAccessibilityState

Returns a ReactTestInstance with matching accessibilityState prop.

import { render } from '@testing-library/react-native';
const { getByA11yState } = render(<Component />);
const element = getByA11yState({ disabled: true });

ByA11Value, ByAccessibilityValue

getByA11yValue, getAllByA11yValue, queryByA11yValue, queryAllByA11yValue, findByA11yValue, findAllByA11yValue getByAccessibilityValue, getAllByAccessibilityValue, queryByAccessibilityValue, queryAllByAccessibilityValue, findByAccessibilityValue, findAllByAccessibilityValue

Returns a ReactTestInstance with matching accessibilityValue prop.

import { render } from '@testing-library/react-native';
const { getByA11yValue } = render(<Component />);
const element = getByA11yValue({ min: 40 });

TextMatch

Most of the query APIs take a TextMatch as an argument, which means the argument can be either a string or regex.

type TextMatchOptions = {
exact?: boolean;
normalizer?: (textToNormalize: string) => string;
trim?: boolean;
collapseWhitespace?: boolean;
};

Examples

Given the following render:

const { getByText } = render(<Text>Hello World</Text>);

Will find a match:

// Matching a string:
getByText('Hello World'); // full string match
getByText('llo Worl', { exact: false }); // substring match
getByText('hello world', { exact: false }); // ignore case-sensitivity
// Matching a regex:
getByText(/World/); // substring match
getByText(/world/i); // substring match, ignore case
getByText(/^hello world$/i); // full string match, ignore case-sensitivity
getByText(/Hello W?oRlD/i); // advanced regex

Will NOT find a match

// substring does not match
getByText('llo Worl');
// full string does not match
getByText('Goodbye World');
-
// case-sensitive regex with different case
getByText(/hello world/);

Precision

Queries that take a TextMatch also accept an object as the final argument that can contain options that affect the precision of string matching:

  • exact: Defaults to true; matches full strings, case-sensitive. When false, matches substrings and is not case-sensitive.
    • exact has no effect on regex argument.
    • In most cases using a regex instead of a string gives you more control over fuzzy matching and should be preferred over { exact: false }.
  • normalizer: An optional function which overrides normalization behavior. See Normalization.

exact option defaults to true but if you want to search for a text slice or make text matching case-insensitive you can override it. That being said we advise you to use regex in more complex scenarios.

Normalization

Before running any matching logic against text, it is automatically normalized. By default, normalization consists of trimming whitespace from the start and end of text, and collapsing multiple adjacent whitespace characters into a single space.

If you want to prevent that normalization, or provide alternative normalization (e.g. to remove Unicode control characters), you can provide a normalizer function in the options object. This function will be given a string and is expected to return a normalized version of that string.

info

Specifying a value for normalizer replaces the built-in normalization, but you can call getDefaultNormalizer to obtain a built-in normalizer, either to adjust that normalization or to call it from your own normalizer.

getDefaultNormalizer take options object which allows the selection of behaviour:

  • trim: Defaults to true. Trims leading and trailing whitespace.
  • collapseWhitespace: Defaults to true. Collapses inner whitespace (newlines, tabs repeated spaces) into a single space.

Normalization Examples

To perform a match against text without trimming:

getByText(node, 'text', {
normalizer: getDefaultNormalizer({ trim: false }),
});

To override normalization to remove some Unicode characters whilst keeping some (but not all) of the built-in normalization behavior:

getByText(node, 'text', {
normalizer: (str) =>
getDefaultNormalizer({ trim: false })(str).replace(/[\u200E-\u200F]*/g, ''),
});

Unit testing helpers

Use sparingly and responsibly, escape hatches here

render from @testing-library/react-native exposes additional queries that should not be used in component integration testing, but some users (like component library creators) interested in unit testing some components may find helpful.

Queries helpful in unit testing

The interface is the same as for other queries, but we won't provide full names so that they're harder to find by search engines.

UNSAFE_ByType

UNSAFE_getByType, UNSAFE_getAllByType, UNSAFE_queryByType, UNSAFE_queryAllByType

Returns a ReactTestInstance with matching a React component type.

caution

This method has been marked unsafe, since it requires knowledge about implementation details of the component. Use responsibly.

UNSAFE_ByProps

UNSAFE_getByProps, UNSAFE_getAllByProps, UNSAFE_queryByProps, UNSAFE_queryAllByProps

Returns a ReactTestInstance with matching props object.

caution

This method has been marked unsafe, since it requires knowledge about implementation details of the component. Use responsibly.

+
// case-sensitive regex with different case
getByText(/hello world/);

Precision

Queries that take a TextMatch also accept an object as the final argument that can contain options that affect the precision of string matching:

  • exact: Defaults to true; matches full strings, case-sensitive. When false, matches substrings and is not case-sensitive.
    • exact has no effect on regex argument.
    • In most cases using a regex instead of a string gives you more control over fuzzy matching and should be preferred over { exact: false }.
  • normalizer: An optional function which overrides normalization behavior. See Normalization.

exact option defaults to true but if you want to search for a text slice or make text matching case-insensitive you can override it. That being said we advise you to use regex in more complex scenarios.

Normalization

Before running any matching logic against text, it is automatically normalized. By default, normalization consists of trimming whitespace from the start and end of text, and collapsing multiple adjacent whitespace characters into a single space.

If you want to prevent that normalization, or provide alternative normalization (e.g. to remove Unicode control characters), you can provide a normalizer function in the options object. This function will be given a string and is expected to return a normalized version of that string.

info

Specifying a value for normalizer replaces the built-in normalization, but you can call getDefaultNormalizer to obtain a built-in normalizer, either to adjust that normalization or to call it from your own normalizer.

getDefaultNormalizer take options object which allows the selection of behaviour:

  • trim: Defaults to true. Trims leading and trailing whitespace.
  • collapseWhitespace: Defaults to true. Collapses inner whitespace (newlines, tabs repeated spaces) into a single space.

Normalization Examples

To perform a match against text without trimming:

getByText(node, 'text', {
normalizer: getDefaultNormalizer({ trim: false }),
});

To override normalization to remove some Unicode characters whilst keeping some (but not all) of the built-in normalization behavior:

getByText(node, 'text', {
normalizer: (str) =>
getDefaultNormalizer({ trim: false })(str).replace(/[\u200E-\u200F]*/g, ''),
});

Unit testing helpers

Use sparingly and responsibly, escape hatches here

render from @testing-library/react-native exposes additional queries that should not be used in component integration testing, but some users (like component library creators) interested in unit testing some components may find helpful.

Queries helpful in unit testing

The interface is the same as for other queries, but we won't provide full names so that they're harder to find by search engines.

UNSAFE_ByType

UNSAFE_getByType, UNSAFE_getAllByType, UNSAFE_queryByType, UNSAFE_queryAllByType

Returns a ReactTestInstance with matching a React component type.

caution

This method has been marked unsafe, since it requires knowledge about implementation details of the component. Use responsibly.

UNSAFE_ByProps

UNSAFE_getByProps, UNSAFE_getAllByProps, UNSAFE_queryByProps, UNSAFE_queryAllByProps

Returns a ReactTestInstance with matching props object.

caution

This method has been marked unsafe, since it requires knowledge about implementation details of the component. Use responsibly.

- + @@ -50,6 +46,6 @@ getByAccessibilityValue, getAllByAccessibilityValue, queryByAccessibilityValue, - + \ No newline at end of file diff --git a/docs/api/index.html b/docs/api/index.html index 2a669aa3..796e390d 100644 --- a/docs/api/index.html +++ b/docs/api/index.html @@ -6,7 +6,7 @@ API | React Native Testing Library - + @@ -14,12 +14,12 @@ - +

API

This page gathers public API of React Native Testing Library along with usage examples.

render

Defined as:

function render(
component: React.Element<any>,
options?: {
/* A React Component that renders `component` as children */
wrapper?: React.ComponentType<any>,
/* You won't often use this, but it's helpful when testing refs */
createNodeMock: (element: React.Element<any>) => any,
}
): RenderResult {}

Deeply renders given React element and returns helpers to query the output components structure.

import { render } from '@testing-library/react-native';
import { QuestionsBoard } from '../QuestionsBoard';
-
test('should verify two questions', () => {
const { queryAllByA11yRole } = render(<QuestionsBoard {...props} />);
const allQuestions = queryAllByA11yRole('header');
+
test('should verify two questions', () => {
const { queryAllByRole } = render(<QuestionsBoard {...props} />);
const allQuestions = queryAllByRole('header');
expect(allQuestions).toHaveLength(2);
});

When using React context providers, like Redux Provider, you'll likely want to wrap rendered component with them. In such cases it's convenient to create your custom render method. Follow this great guide on how to set this up.

The render method returns a RenderResult object that has a few properties:

...queries

The most important feature of render is providing a set of helpful queries that allow you to find certain elements in the view hierarchy.

See Queries for a complete list.

Example

import { render } from '@testing-library/react-native';
const { getByText, queryByA11yStates } = render(<Component />);

update

Also available under rerender alias

update(element: React.Element<any>): void
rerender(element: React.Element<any>): void

Re-render the in-memory tree with a new root element. This simulates a React update at the root. If the new element has the same type and key as the previous element, the tree will be updated; otherwise, it will re-mount a new tree. This is useful when testing for componentDidUpdate behavior, by passing updated props to the component.

Example code

unmount

unmount(): void

Unmount the in-memory tree, triggering the appropriate lifecycle events.

note

Usually you should not need to call unmount as it is done automatically if your test runner supports afterEach hook (like Jest, mocha, Jasmine).

debug

debug(message?: string): void

Pretty prints deeply rendered component passed to render with optional message on top.

const { debug } = render(<Component />);
debug('optional message');

logs optional message and colored JSX:

optional message
@@ -46,11 +46,11 @@
test('waiting for an Banana to be ready', async () => {
const { getByText } = render(<Banana />);
await waitFor(() => getByText('Banana ready'));
});
info

In order to properly use waitFor you need at least React >=16.9.0 (featuring async act) or React Native >=0.61 (which comes with React >=16.9.0).

waitForElementToBeRemoved

Defined as:

function waitForElementToBeRemoved<T>(
expectation: () => T,
{ timeout: number = 4500, interval: number = 50 }
): Promise<T> {}

Waits for non-deterministic periods of time until queried element is removed or times out. waitForElementToBeRemoved periodically calls expectation every interval milliseconds to determine whether the element has been removed or not.

import {
render,
waitForElementToBeRemoved,
} from '@testing-library/react-native';
test('waiting for an Banana to be removed', async () => {
const { getByText } = render(<Banana />);
-
await waitForElementToBeRemoved(() => getByText('Banana ready'));
});

This method expects that the element is initally present in the render tree and then is removed from it. If the element is not present when you call this method it throws an error.

You can use any of getBy, getAllBy, queryBy and queryAllBy queries for expectation parameter.

info

In order to properly use waitForElementToBeRemoved you need at least React >=16.9.0 (featuring async act) or React Native >=0.61 (which comes with React >=16.9.0).

within, getQueriesForElement

Defined as:

function within(instance: ReactTestInstance): Queries
function getQueriesForElement(instance: ReactTestInstance): Queries

within (also available as getQueriesForElement alias) performs queries scoped to given element.

note

Please note that additional render specific operations like update, unmount, debug, toJSON are not included.

const detailsScreen = within(getByA11yHint('Details Screen'));
expect(detailsScreen.getByText('Some Text')).toBeTruthy();
expect(detailsScreen.getByDisplayValue('Some Value')).toBeTruthy();
expect(detailsScreen.queryByA11yLabel('Some Label')).toBeTruthy();
await expect(detailsScreen.findByA11yHint('Some Label')).resolves.toBeTruthy();

Use cases for scoped queries include:

  • queries scoped to a single item inside a FlatList containing many items
  • queries scoped to a single screen in tests involving screen transitions (e.g. with react-navigation)

query APIs

Each of the get APIs listed in the render section above have a complimentary query API. The get APIs will throw errors if a proper node cannot be found. This is normally the desired effect. However, if you want to make an assertion that an element is not present in the hierarchy, then you can use the query API instead:

import { render } from '@testing-library/react-native';
+
await waitForElementToBeRemoved(() => getByText('Banana ready'));
});

This method expects that the element is initally present in the render tree and then is removed from it. If the element is not present when you call this method it throws an error.

You can use any of getBy, getAllBy, queryBy and queryAllBy queries for expectation parameter.

info

In order to properly use waitForElementToBeRemoved you need at least React >=16.9.0 (featuring async act) or React Native >=0.61 (which comes with React >=16.9.0).

within, getQueriesForElement

Defined as:

function within(instance: ReactTestInstance): Queries
function getQueriesForElement(instance: ReactTestInstance): Queries

within (also available as getQueriesForElement alias) performs queries scoped to given element.

note

Please note that additional render specific operations like update, unmount, debug, toJSON are not included.

const detailsScreen = within(getByA11yHint('Details Screen'));
expect(detailsScreen.getByText('Some Text')).toBeTruthy();
expect(detailsScreen.getByDisplayValue('Some Value')).toBeTruthy();
expect(detailsScreen.queryByLabelText('Some Label')).toBeTruthy();
await expect(detailsScreen.findByA11yHint('Some Label')).resolves.toBeTruthy();

Use cases for scoped queries include:

  • queries scoped to a single item inside a FlatList containing many items
  • queries scoped to a single screen in tests involving screen transitions (e.g. with react-navigation)

query APIs

Each of the get APIs listed in the render section above have a complimentary query API. The get APIs will throw errors if a proper node cannot be found. This is normally the desired effect. However, if you want to make an assertion that an element is not present in the hierarchy, then you can use the query API instead:

import { render } from '@testing-library/react-native';
const { queryByText } = render(<Form />);
const submitButton = queryByText('submit');
expect(submitButton).toBeNull(); // it doesn't exist

queryAll APIs

Each of the query APIs have a corresponding queryAll version that always returns an Array of matching nodes. getAll is the same but throws when the array has a length of 0.

import { render } from '@testing-library/react-native';
const { queryAllByText } = render(<Forms />);
const submitButtons = queryAllByText('submit');
expect(submitButtons).toHaveLength(3); // expect 3 elements

act

Useful function to help testing components that use hooks API. By default any render, update, fireEvent, and waitFor calls are wrapped by this function, so there is no need to wrap it manually. This method is re-exported from react-test-renderer.

- + @@ -58,6 +58,6 @@ - + \ No newline at end of file diff --git a/docs/eslint-plugin-testing-library/index.html b/docs/eslint-plugin-testing-library/index.html index 8bdd9d21..9183d612 100644 --- a/docs/eslint-plugin-testing-library/index.html +++ b/docs/eslint-plugin-testing-library/index.html @@ -6,7 +6,7 @@ ESLint Plugin Testing Library Compatibility | React Native Testing Library - + @@ -20,7 +20,7 @@

ESLint Plugin Testing Library Compatibility

Most of the rules of the eslint-plugin-testing-library are compatible with this library except the followings:

Also, some rules have become useless, unless maybe you're using an old version of the library:

To get the rule consistent-data-testid to work, you need to configure it to check the testID attribute by adding the following in your eslint config file, the testIdPattern being whichever pattern you want to enforce:

{
"testing-library/consistent-data-testid": [
2,
{
"testIdAttribute": ["testID"],
"testIdPattern": "^TestId(__[A-Z]*)?$"
}
]
}
- + diff --git a/docs/getting-started/index.html b/docs/getting-started/index.html index 6d0dfec2..c6fa1616 100644 --- a/docs/getting-started/index.html +++ b/docs/getting-started/index.html @@ -6,7 +6,7 @@ Getting Started | React Native Testing Library - + @@ -14,18 +14,18 @@ - +

Getting Started

The problem

You want to write maintainable tests for your React Native components. As a part of this goal, you want your tests to avoid including implementation details of your components and rather focus on making your tests give you the confidence for which they are intended. As part of this, you want your testbase to be maintainable in the long run so refactors of your components (changes to implementation but not functionality) don't break your tests and slow you and your team down.

This solution

The React Native Testing Library (RNTL) is a lightweight solution for testing React Native components. It provides light utility functions on top of react-test-renderer, in a way that encourages better testing practices. Its primary guiding principle is:

The more your tests resemble the way your software is used, the more confidence they can give you.

This project is inspired by React Testing Library. Tested to work with Jest, but it should work with other test runners as well.

You can find the source of QuestionsBoard component and this example here.

Installation

Open a Terminal in your project's folder and run:

Using yarn

yarn add --dev @testing-library/react-native

Using npm

npm install --save-dev @testing-library/react-native

This library has a peerDependencies listing for react-test-renderer and, of course, react. Make sure to install them too!

info

In order to properly use helpers for async tests (findBy queries and waitFor) you need at least React >=16.9.0 (featuring async act) or React Native >=0.61 (which comes with React >=16.9.0).

Additional Jest matchers

In order to use addtional React Native-specific jest matchers from @testing-library/jest-native package add it to your project:

Using yarn

yarn add --dev @testing-library/jest-native

Using npm

npm install --save-dev @testing-library/jest-native

Then automatically add it to your jest tests by using setupFilesAfterEnv option in your Jest configuration (it's usually located either in package.json under "jest" key or in a jest.config.js file):

{
"preset": "react-native",
"setupFilesAfterEnv": ["@testing-library/jest-native/extend-expect"]
}

Flow

Note for Flow users โ€“ you'll also need to install typings for react-test-renderer:

flow-typed install react-test-renderer

Example

import { render, fireEvent } from '@testing-library/react-native';
import { QuestionsBoard } from '../QuestionsBoard';
test('form submits two answers', () => {
const allQuestions = ['q1', 'q2'];
const mockFn = jest.fn();
-
const { getAllByA11yLabel, getByText } = render(
<QuestionsBoard questions={allQuestions} onSubmit={mockFn} />
);
-
const answerInputs = getAllByA11yLabel('answer input');
+
const { getAllByLabelText, getByText } = render(
<QuestionsBoard questions={allQuestions} onSubmit={mockFn} />
);
+
const answerInputs = getAllByLabelText('answer input');
fireEvent.changeText(answerInputs[0], 'a1');
fireEvent.changeText(answerInputs[1], 'a2');
fireEvent.press(getByText('Submit'));
expect(mockFn).toBeCalledWith({
'1': { q: 'q1', a: 'a1' },
'2': { q: 'q2', a: 'a2' },
});
});

You can find the source of QuestionsBoard component and this example here.

- + @@ -33,6 +33,6 @@ - + \ No newline at end of file diff --git a/docs/how-should-i-query/index.html b/docs/how-should-i-query/index.html index 11c0f33e..e52202e3 100644 --- a/docs/how-should-i-query/index.html +++ b/docs/how-should-i-query/index.html @@ -6,7 +6,7 @@ How Should I Query? | React Native Testing Library - + @@ -14,13 +14,13 @@ - +
-

How Should I Query?

Priority

Based on the Guiding Principles, your test should resemble how users interact with your code (component, page, etc.) as much as possible. With this in mind, we recommend this order of priority:

  1. Queries Accessible to Everyone queries that reflect the experience of visual users as well as those that use assistive technology
    • getByText: This is the number 1 method a user finds any visible text on interactive and non-interactive elements.
    • getByDisplayValue: Useful for the current value of a TextInput.
    • getByPlaceholderText: Only useful for targeting a placeholder of a TextInput.
    • getByLabelText: This can be used to query every element that is exposed in the accessibility tree as a label, usually when there's no visible text.
    • getByHintText: This can be used to query every element that is exposed in the accessibility tree as a hint. Make sure it also has a label set.
    • getByAccessibilityState: This can be used to query every element that is exposed in the accessibility tree as a state of an interactive element, like a checkbox.
    • getByAccessibilityValue: This can be used to query every element that is exposed in the accessibility tree as a value on a range, like a slider.
  2. Queries Users Can Infer
    • getByRole: This can be used to query every element that is exposed in the accessibility tree as a role, like buttons or images.
  3. Test IDs
    • getByTestId: The user cannot see (or hear) these, so this is only recommended for cases where you can't match by text or it doesn't make sense
+

How Should I Query?

Priority

Based on the Guiding Principles, your test should resemble how users interact with your code (component, page, etc.) as much as possible. With this in mind, we recommend this order of priority:

  1. Queries Accessible to Everyone queries that reflect the experience of visual users as well as those that use assistive technology
    • getByText: This is the number 1 method a user finds any visible text on interactive and non-interactive elements.
    • getByDisplayValue: Useful for the current value of a TextInput.
    • getByPlaceholderText: Only useful for targeting a placeholder of a TextInput.
    • getByLabelText: This can be used to query every element that is exposed in the accessibility tree as a label, usually when there's no visible text.
    • getByHintText: This can be used to query every element that is exposed in the accessibility tree as a hint. Make sure it also has a label set.
    • getByAccessibilityState: This can be used to query every element that is exposed in the accessibility tree as a state of an interactive element, like a checkbox.
    • getByAccessibilityValue: This can be used to query every element that is exposed in the accessibility tree as a value on a range, like a slider.
  2. Queries Users Can Infer
    • getByRole: This can be used to query every element that is exposed in the accessibility tree as a role, like buttons or images.
  3. Test IDs
    • getByTestId: The user cannot see (or hear) these, so this is only recommended for cases where you can't match by text or it doesn't make sense
- + @@ -28,6 +28,6 @@ - + \ No newline at end of file diff --git a/docs/migration-v2/index.html b/docs/migration-v2/index.html index 567359ac..967c1459 100644 --- a/docs/migration-v2/index.html +++ b/docs/migration-v2/index.html @@ -6,7 +6,7 @@ Migration to 2.0 | React Native Testing Library - + @@ -22,7 +22,7 @@
export function shallow(instance: ReactTestInstance | React.Element<any>) {
const renderer = new ShallowRenderer();
renderer.render(React.createElement(instance.type, instance.props));
return { output: renderer.getRenderOutput() };
}

Removed functions

Following query functions have been removed after being deprecated for more than a year now:

  • getByName
  • getAllByName
  • queryByName
  • queryAllByName

The *ByType and *ByProps queries has been prefixed with UNSAFE_. These UNSAFE_ functions are not planned for removal in future versions but their usage is discouraged. You can rename them using global search/replace in your project:

  • getByType -> UNSAFE_getByType
  • getAllByType -> UNSAFE_getAllByType
  • queryByType -> UNSAFE_queryByType
  • queryAllByType -> UNSAFE_queryAllByType
  • getByProps -> UNSAFE_getByProps
  • getAllByProps -> UNSAFE_getAllByProps
  • queryByProps -> UNSAFE_queryByProps
  • queryAllByProps -> UNSAFE_queryAllByProps

Some ByTestId queries behavior changes

In version 1.x the getByTestId and queryByTestId queries could return non-native instances. This was a serious bug. Other query functions like getAllByTestId, queryAllByTestId, findByTestId and findAllByTestId didn't have this issue. These correctly returned only native components instances (e.g. View, Text, etc) that got the testID.

In v2 we fixed this inconsistency, which may result in failing tests, if you relied on this behavior. There are few ways to handle these failures:

  • pass the testID prop down so it can reach a native component, like View or Text
  • replace testID with proper accessibilityHint or accessibilityLabel if it benefits the user
  • use safe queries like *ByText or *ByA11yHint

Deprecated flushMicrotasksQueue

We have deprecated flushMicrotasksQueue and plan to remove it in the next major. We have better alternatives available for helping you write async tests โ€“ findBy async queries and waitFor helper.

If you can't or don't want to migrate your tests, don't worry. You can use the same implementation we have today:

function flushMicrotasksQueue() {
return new Promise((resolve) => setImmediate(resolve));
}
- + diff --git a/docs/migration-v7/index.html b/docs/migration-v7/index.html index f080f8b3..2ac5bb13 100644 --- a/docs/migration-v7/index.html +++ b/docs/migration-v7/index.html @@ -6,7 +6,7 @@ Migration to 7.0 | React Native Testing Library - + @@ -20,7 +20,7 @@

Migration to 7.0

caution

We renamed the react-native-testing-library npm package to @testing-library/react-native, officially joining the "Testing Library" family ๐ŸŽ‰.

As the version 7.0 involves merging two libraries together, there are two variants for migration guide, dependent on library you used previously:

Guide for react-native-testing-library users

This guide describes steps necessary to migrate from React Native Testing Library v2.x or v6.0 to v7.0.

Renaming the library

  1. Install @testing-library/react-native.
  2. Uninstall react-native-testing-library.
  3. Rename all references of react-native-testing-library to @testing-library/react-native.

You may have noticed a strange v2 to v7 upgrade, skipping versions 3, 4, 5 and 6. This is because we renamed the react-native-testing-library npm package to @testing-library/react-native, officially joining the "Testing Library" family ๐ŸŽ‰. We're merging existing two libraries into a single one. The native-testing-library repository, which had v6, will soon be archived and using @testing-library/react-native below v7, sourced from mentioned repository, is deprecated.

For branding purposes we keep the "React Native Testing Library" name, similar to "React Testing Library". Only the npm published package is changing. The code repository also stays the same under Callstack governance.

New aliases

To improve compatibility with React Testing Library, and ease the migration for @testing-library/react-native users using version below v7, we've introduced new aliases to our accessibility queries:

  • ByLabelText aliasing ByA11yLabel queries
  • ByHintText aliasing ByA11yHint queries
  • ByRole aliasing ByA11yRole queries

We like the new names and consider removing the aliases in future releases.

Renaming ByPlaceholder queries

To improve compatibility with React Testing Library, and to ease the migration for @testing-library/react-native users using version below v7, we've renamed following queries:

  • ByPlaceholder -> ByPlaceholderText

Please replace all occurrences of these queries in your codebase.

fireEvent support for disabled components

To improve compatibility with the real React Native environment fireEvent now performs checks whether the component is "disabled" before firing an event on it. It uses the Responder system to establish should the event fire, which resembles the actual React Native runtime closer than we used to.

If your code contained any workarounds for preventing events firing on disabled events, you should now be able to remove them.

Guide for @testing-library/react-native users

This guide describes steps necessary to migrate from @testing-library/react-native from v6.0 to v7.0. Although the name stays the same, this is a different library, sourced at Callstack GitHub repository. We made sure the upgrade path is as easy for you as possible.

Renaming "wait" helpers

The wait and waitForElement helpers are replaced by waitFor. Please rename all occurrences of these in your codebase.

Changes to ByTestId queries

The ByTestId queries don't accept RegExps. Please use strings instead. We're happy to accept PRs adding this functionality :).

No ByTitle queries

Our library doesn't implement ByTitle queries, which are targetting components with title prop, specifically Button and RefreshControl. If your tests only use ByTitle to target Button components, you can replace them with ByText queries, since React Native renders Text under the hood.

If you need to query RefreshControl component and can't figure out other way around it, you can use e.g. UNSAFE_getByProps({title}) query.

No custom Jest configuration

Use the official React Native preset for Jest:

{
"jest": {
- "preset": "@testing-library/react-native"
+ "preset": "react-native"
}
}

We're told this also speeds up your tests startup on cold cache. Using official preset has another benefit โ€“ the library is compatible with any version of React Native without introducing breaking changes.

Cleanup is included by default

Cleaning up (unmounting) components after each test is included by default in the same manner as in React Testing Library. Please remove this setup file from Jest config:

{
"jest": {
- "setupFilesAfterEnv": ["@testing-library/react-native/cleanup-after-each"]
}
}

You can opt-out of this behavior by running tests with RNTL_SKIP_AUTO_CLEANUP=true flag or importing from @testing-library/react-native/pure. We encourage you to keep the default though.

No NativeTestInstance abstraction

We don't provide any abstraction over ReactTestInstance returned by queries, but allow to use it directly to access queried component's props or type for that example.

No container nor baseElement returned from render

There's no container returned from the render function. If you must, use react-test-renderer directly, although we advise against doing so. We also don't implement baseElement because of that, since there's no document.documentElement nor container.

Firing events changes

There are slight differences in how fireEvent works in both libraries:

  1. Our library doesn't perform validation checks for events fired upon tested components.
  2. Signature is different:
    -fireEvent[eventName](node: FiberRoot, eventProperties: NativeTestEvent)
    +fireEvent(element: ReactTestInstance, eventName: string, ...data: Array<any>)
  3. There is no NativeTestEvent - second and rest arguments are used instead.
  4. There are only 3 short-hand events: fireEvent.press, fireEvent.changeText and fireEvent.scroll. For all other or custom events you can use the base signature.
- + diff --git a/docs/migration-v9/index.html b/docs/migration-v9/index.html index a82e2fd9..d4d1a17b 100644 --- a/docs/migration-v9/index.html +++ b/docs/migration-v9/index.html @@ -6,7 +6,7 @@ Migration to 9.0 | React Native Testing Library - + @@ -23,7 +23,7 @@
const {getByText} = render(<Text>Hello <Text>world</Text</Text>)
within(getByText('Hello', {exact: false})).getByText('world')

Future plans

This release changes a lot of internal logic in the library, paving the way for more improvements to bring us closer to our web counterpart, with a possibly better story for accessibility queries.

We're also migrating the codebase to TypeScript. Please let us know if you're interested in helping us with this effort.

Stay safe!

- + diff --git a/docs/react-navigation/index.html b/docs/react-navigation/index.html index f733ff33..682967ea 100644 --- a/docs/react-navigation/index.html +++ b/docs/react-navigation/index.html @@ -6,7 +6,7 @@ React Navigation | React Native Testing Library - + @@ -59,7 +59,7 @@
fireEvent(button, 'press');
const newScreen = await findByText('This is the notifications screen');
expect(newScreen).toBeTruthy();
});
});

Running tests

To run the tests, place a test script inside your package.json

{
"scripts": {
"test": "jest"
}
}

And run the test script with npm test or yarn test.

- + diff --git a/docs/redux-integration/index.html b/docs/redux-integration/index.html index 9003d7a0..af9cd33b 100644 --- a/docs/redux-integration/index.html +++ b/docs/redux-integration/index.html @@ -6,7 +6,7 @@ Redux Integration | React Native Testing Library - + @@ -38,7 +38,7 @@
const buttons = getAllByText('Delete');
expect(buttons.length).toBe(2);
fireEvent.press(buttons[0]);
expect(getAllByText('Delete').length).toBe(1);
});
});

Running tests

To run the tests, place a test script inside your package.json

{
"scripts": {
"test": "jest"
}
}

And run the test script with npm test or yarn test.

- + diff --git a/f2d2b077.9f8a1547.js b/f2d2b077.9f8a1547.js deleted file mode 100644 index 3112f9ef..00000000 --- a/f2d2b077.9f8a1547.js +++ /dev/null @@ -1 +0,0 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[14],{73:function(e,t,a){"use strict";a.r(t),a.d(t,"frontMatter",(function(){return c})),a.d(t,"metadata",(function(){return l})),a.d(t,"rightToc",(function(){return s})),a.d(t,"default",(function(){return b}));var i=a(1),r=a(6),n=(a(0),a(80)),c={id:"how-should-i-query",title:"How Should I Query?"},l={unversionedId:"how-should-i-query",id:"how-should-i-query",isDocsHomePage:!1,title:"How Should I Query?",description:"Priority",source:"@site/docs/HowShouldIQuery.md",permalink:"/react-native-testing-library/docs/how-should-i-query",editUrl:"https://github.com/callstack/react-native-testing-library/blob/main/docs/HowShouldIQuery.md",sidebar:"docs",previous:{title:"Migration to 2.0",permalink:"/react-native-testing-library/docs/migration-v2"},next:{title:"ESLint Plugin Testing Library Compatibility",permalink:"/react-native-testing-library/docs/eslint-plugin-testing-library"}},s=[{value:"Priority",id:"priority",children:[]}],o={rightToc:s};function b(e){var t=e.components,a=Object(r.a)(e,["components"]);return Object(n.b)("wrapper",Object(i.a)({},o,a,{components:t,mdxType:"MDXLayout"}),Object(n.b)("h2",{id:"priority"},"Priority"),Object(n.b)("p",null,"Based on the ",Object(n.b)("a",Object(i.a)({parentName:"p"},{href:"https://testing-library.com/docs/guiding-principles"}),"Guiding Principles"),", your test should resemble how users interact with your code (component, page, etc.) as much as possible. With this in mind, we recommend this order of priority:"),Object(n.b)("ol",null,Object(n.b)("li",{parentName:"ol"},Object(n.b)("strong",{parentName:"li"},"Queries Accessible to Everyone")," queries that reflect the experience of visual users as well as those that use assistive technology",Object(n.b)("ul",{parentName:"li"},Object(n.b)("li",{parentName:"ul"},Object(n.b)("a",Object(i.a)({parentName:"li"},{href:"https://callstack.github.io/react-native-testing-library/docs/api-queries#bytext"}),Object(n.b)("inlineCode",{parentName:"a"},"getByText")),": This is the number 1 method a user finds any visible text on interactive and non-interactive elements."),Object(n.b)("li",{parentName:"ul"},Object(n.b)("a",Object(i.a)({parentName:"li"},{href:"https://callstack.github.io/react-native-testing-library/docs/api-queries#bydisplayvalue"}),Object(n.b)("inlineCode",{parentName:"a"},"getByDisplayValue")),": Useful for the current value of a ",Object(n.b)("inlineCode",{parentName:"li"},"TextInput"),"."),Object(n.b)("li",{parentName:"ul"},Object(n.b)("a",Object(i.a)({parentName:"li"},{href:"https://callstack.github.io/react-native-testing-library/docs/api-queries#byplaceholdertext"}),Object(n.b)("inlineCode",{parentName:"a"},"getByPlaceholderText")),": Only useful for targeting a placeholder of a ",Object(n.b)("inlineCode",{parentName:"li"},"TextInput"),"."),Object(n.b)("li",{parentName:"ul"},Object(n.b)("a",Object(i.a)({parentName:"li"},{href:"https://callstack.github.io/react-native-testing-library/docs/api-queries#bya11ylabel-byaccessibilitylabel-bylabeltext"}),Object(n.b)("inlineCode",{parentName:"a"},"getByLabelText")),": This can be used to query every element that is exposed in the accessibility tree as a label, usually when there's no visible text."),Object(n.b)("li",{parentName:"ul"},Object(n.b)("a",Object(i.a)({parentName:"li"},{href:"https://callstack.github.io/react-native-testing-library/docs/api-queries#bya11yhint-byaccessibilityhint-byhinttext"}),Object(n.b)("inlineCode",{parentName:"a"},"getByHintText")),": This can be used to query every element that is exposed in the accessibility tree as a hint. Make sure it also has a label set."),Object(n.b)("li",{parentName:"ul"},Object(n.b)("a",Object(i.a)({parentName:"li"},{href:"https://callstack.github.io/react-native-testing-library/docs/api-queries#bya11ystate-byaccessibilitystate"}),Object(n.b)("inlineCode",{parentName:"a"},"getByAccessibilityState")),": This can be used to query every element that is exposed in the accessibility tree as a state of an interactive element, like a checkbox."),Object(n.b)("li",{parentName:"ul"},Object(n.b)("a",Object(i.a)({parentName:"li"},{href:"https://callstack.github.io/react-native-testing-library/docs/api-queries#bya11value-byaccessibilityvalue"}),Object(n.b)("inlineCode",{parentName:"a"},"getByAccessibilityValue")),": This can be used to query every element that is exposed in the accessibility tree as a value on a range, like a slider."))),Object(n.b)("li",{parentName:"ol"},Object(n.b)("strong",{parentName:"li"},"Queries Users Can Infer"),Object(n.b)("ul",{parentName:"li"},Object(n.b)("li",{parentName:"ul"},Object(n.b)("a",Object(i.a)({parentName:"li"},{href:"https://callstack.github.io/react-native-testing-library/docs/api-queries#bya11yrole-byaccessibilityrole-byrole"}),Object(n.b)("inlineCode",{parentName:"a"},"getByRole")),": This can be used to query every element that is exposed in the accessibility tree as a role, like buttons or images."))),Object(n.b)("li",{parentName:"ol"},Object(n.b)("strong",{parentName:"li"},"Test IDs"),Object(n.b)("ul",{parentName:"li"},Object(n.b)("li",{parentName:"ul"},Object(n.b)("a",Object(i.a)({parentName:"li"},{href:"https://callstack.github.io/react-native-testing-library/docs/api-queries#bytestid"}),Object(n.b)("inlineCode",{parentName:"a"},"getByTestId")),": The user cannot see (or hear) these, so this is only recommended for cases where you can't match by text or it doesn't make sense")))))}b.isMDXComponent=!0},80:function(e,t,a){"use strict";a.d(t,"a",(function(){return u})),a.d(t,"b",(function(){return h}));var i=a(0),r=a.n(i);function n(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function c(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,i)}return a}function l(e){for(var t=1;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var o=r.a.createContext({}),b=function(e){var t=r.a.useContext(o),a=t;return e&&(a="function"==typeof e?e(t):l({},t,{},e)),a},u=function(e){var t=b(e.components);return r.a.createElement(o.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.a.createElement(r.a.Fragment,{},t)}},y=Object(i.forwardRef)((function(e,t){var a=e.components,i=e.mdxType,n=e.originalType,c=e.parentName,o=s(e,["components","mdxType","originalType","parentName"]),u=b(a),y=i,h=u["".concat(c,".").concat(y)]||u[y]||p[y]||n;return a?r.a.createElement(h,l({ref:t},o,{components:a})):r.a.createElement(h,l({ref:t},o))}));function h(e,t){var a=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var n=a.length,c=new Array(n);c[0]=y;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l.mdxType="string"==typeof e?e:i,c[1]=l;for(var o=2;o=0||(i[a]=e[a]);return i}(e,t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(i[a]=e[a])}return i}var s=i.a.createContext({}),b=function(e){var t=i.a.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):l({},t,{},e)),a},u=function(e){var t=b(e.components);return i.a.createElement(s.Provider,{value:t},e.children)},p={inlineCode:"code",wrapper:function(e){var t=e.children;return i.a.createElement(i.a.Fragment,{},t)}},y=Object(r.forwardRef)((function(e,t){var a=e.components,r=e.mdxType,n=e.originalType,c=e.parentName,s=o(e,["components","mdxType","originalType","parentName"]),u=b(a),y=r,h=u["".concat(c,".").concat(y)]||u[y]||p[y]||n;return a?i.a.createElement(h,l({ref:t},s,{components:a})):i.a.createElement(h,l({ref:t},s))}));function h(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var n=a.length,c=new Array(n);c[0]=y;var l={};for(var o in t)hasOwnProperty.call(t,o)&&(l[o]=t[o]);l.originalType=e,l.mdxType="string"==typeof e?e:r,c[1]=l;for(var s=2;s React Native Testing Library | React Native Testing Library - + @@ -16,7 +16,7 @@

React Native Testing Library

Helps you to write better tests with less effort.

Get Started
Maintainable

Maintainable

Write maintainable tests for your React Native apps

Reliable

Reliable

Promotes testing public APIs and avoiding implementation details

Community Driven

Community Driven

Supported by React Native community and its core contributors

Like the project? โš›๏ธ Join the team who does amazing stuff for clients and drives React Native Open Source! ๐Ÿ”ฅ
- + diff --git a/runtime~main.da14aa78.js b/runtime~main.6f8f5c93.js similarity index 94% rename from runtime~main.da14aa78.js rename to runtime~main.6f8f5c93.js index 4cc9e674..08f65b64 100644 --- a/runtime~main.da14aa78.js +++ b/runtime~main.6f8f5c93.js @@ -1 +1 @@ -!function(e){function r(r){for(var n,c,f=r[0],u=r[1],i=r[2],d=0,p=[];d Search the documentation | React Native Testing Library - + @@ -16,7 +16,7 @@

Search the documentation

- +