From 14ca0cd07908ca5510ebecf08ff1e14bd1bb4492 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 12 Mar 2024 10:37:37 +0000 Subject: [PATCH] deploy: bab4097836aa903ff4cc3cd441bf99252f623cf5 --- 404.html | 2 +- ...581a0.65ef15c7.js => 698581a0.eb08a5e7.js} | 2 +- ...a9e12.7c7fa4d8.js => 77ba9e12.319083fc.js} | 2 +- assets/js/7ad239b9.9d775967.js | 1 - assets/js/7ad239b9.d78ac751.js | 1 + ...06ab1.a1119996.js => add06ab1.50727a9c.js} | 2 +- assets/js/c8229a80.1e5ae667.js | 1 + assets/js/c8229a80.87ec1e8f.js | 1 - assets/js/d77361a5.9a82e889.js | 1 - assets/js/d77361a5.ebc4b2b7.js | 1 + ...ec364.e1bd5bf9.js => f69ec364.1556e56b.js} | 2 +- assets/js/runtime~main.33c6f488.js | 1 + assets/js/runtime~main.e24eefd6.js | 1 - docs/api-queries.html | 6 +++--- docs/api.html | 20 +++++++++---------- docs/community-resources.html | 4 ++-- docs/eslint-plugin-testing-library.html | 2 +- docs/faq.html | 2 +- docs/getting-started.html | 2 +- docs/how-should-i-query.html | 2 +- docs/jest-matchers.html | 2 +- docs/migration-jest-native.html | 2 +- docs/migration-v11.html | 4 ++-- docs/migration-v12.html | 2 +- docs/migration-v2.html | 6 +++--- docs/migration-v7.html | 2 +- docs/migration-v9.html | 4 ++-- docs/react-navigation.html | 2 +- docs/redux-integration.html | 4 ++-- docs/testing-env.html | 2 +- docs/troubleshooting.html | 2 +- docs/understanding-act.html | 2 +- docs/user-event.html | 2 +- index.html | 2 +- search.html | 2 +- 35 files changed, 48 insertions(+), 48 deletions(-) rename assets/js/{698581a0.65ef15c7.js => 698581a0.eb08a5e7.js} (53%) rename assets/js/{77ba9e12.7c7fa4d8.js => 77ba9e12.319083fc.js} (58%) delete mode 100644 assets/js/7ad239b9.9d775967.js create mode 100644 assets/js/7ad239b9.d78ac751.js rename assets/js/{add06ab1.a1119996.js => add06ab1.50727a9c.js} (55%) create mode 100644 assets/js/c8229a80.1e5ae667.js delete mode 100644 assets/js/c8229a80.87ec1e8f.js delete mode 100644 assets/js/d77361a5.9a82e889.js create mode 100644 assets/js/d77361a5.ebc4b2b7.js rename assets/js/{f69ec364.e1bd5bf9.js => f69ec364.1556e56b.js} (79%) create mode 100644 assets/js/runtime~main.33c6f488.js delete mode 100644 assets/js/runtime~main.e24eefd6.js diff --git a/404.html b/404.html index 523a39ca..6adb883f 100644 --- a/404.html +++ b/404.html @@ -4,7 +4,7 @@ Page Not Found | React Native Testing Library - + diff --git a/assets/js/698581a0.65ef15c7.js b/assets/js/698581a0.eb08a5e7.js similarity index 53% rename from assets/js/698581a0.65ef15c7.js rename to assets/js/698581a0.eb08a5e7.js index 83ef6f11..afcdfedc 100644 --- a/assets/js/698581a0.65ef15c7.js +++ b/assets/js/698581a0.eb08a5e7.js @@ -1 +1 @@ -"use strict";(self.webpackChunkreact_native_testing_library_website=self.webpackChunkreact_native_testing_library_website||[]).push([[494],{2063:(e,n,i)=>{i.d(n,{Z:()=>o});i(7294);var t=i(1351);const r={tableOfContentsInline:"tableOfContentsInline_prmo"};var s=i(5893);function o(e){let{toc:n,minHeadingLevel:i,maxHeadingLevel:o}=e;return(0,s.jsx)("div",{className:r.tableOfContentsInline,children:(0,s.jsx)(t.Z,{toc:n,minHeadingLevel:i,maxHeadingLevel:o,className:"table-of-contents",linkClassName:null})})}},1351:(e,n,i)=>{i.d(n,{Z:()=>p});var t=i(7294),r=i(6793);function s(e){const n=e.map((e=>({...e,parentIndex:-1,children:[]}))),i=Array(7).fill(-1);n.forEach(((e,n)=>{const t=i.slice(2,e.level);e.parentIndex=Math.max(...t),i[e.level]=n}));const t=[];return n.forEach((e=>{const{parentIndex:i,...r}=e;i>=0?n[i].children.push(r):t.push(r)})),t}function o(e){let{toc:n,minHeadingLevel:i,maxHeadingLevel:t}=e;return n.flatMap((e=>{const n=o({toc:e.children,minHeadingLevel:i,maxHeadingLevel:t});return function(e){return e.level>=i&&e.level<=t}(e)?[{...e,children:n}]:n}))}function l(e){const n=e.getBoundingClientRect();return n.top===n.bottom?l(e.parentNode):n}function c(e,n){var i;let{anchorTopOffset:t}=n;const r=e.find((e=>l(e).top>=t));if(r){var s;return function(e){return e.top>0&&e.bottom{e.current=n?0:document.querySelector(".navbar").clientHeight}),[n]),e}function a(e){const n=(0,t.useRef)(void 0),i=d();(0,t.useEffect)((()=>{if(!e)return()=>{};const{linkClassName:t,linkActiveClassName:r,minHeadingLevel:s,maxHeadingLevel:o}=e;function l(){const e=function(e){return Array.from(document.getElementsByClassName(e))}(t),l=function(e){let{minHeadingLevel:n,maxHeadingLevel:i}=e;const t=[];for(let r=n;r<=i;r+=1)t.push("h"+r+".anchor");return Array.from(document.querySelectorAll(t.join()))}({minHeadingLevel:s,maxHeadingLevel:o}),d=c(l,{anchorTopOffset:i.current}),a=e.find((e=>d&&d.id===function(e){return decodeURIComponent(e.href.substring(e.href.indexOf("#")+1))}(e)));e.forEach((e=>{!function(e,i){i?(n.current&&n.current!==e&&n.current.classList.remove(r),e.classList.add(r),n.current=e):e.classList.remove(r)}(e,e===a)}))}return document.addEventListener("scroll",l),document.addEventListener("resize",l),l(),()=>{document.removeEventListener("scroll",l),document.removeEventListener("resize",l)}}),[e,i])}var h=i(8746),u=i(5893);function x(e){let{toc:n,className:i,linkClassName:t,isChild:r}=e;return n.length?(0,u.jsx)("ul",{className:r?void 0:i,children:n.map((e=>(0,u.jsxs)("li",{children:[(0,u.jsx)(h.Z,{to:"#"+e.id,className:null!=t?t:void 0,dangerouslySetInnerHTML:{__html:e.value}}),(0,u.jsx)(x,{isChild:!0,toc:e.children,className:i,linkClassName:t})]},e.id)))}):null}const m=t.memo(x);function p(e){let{toc:n,className:i="table-of-contents table-of-contents__left-border",linkClassName:l="table-of-contents__link",linkActiveClassName:c,minHeadingLevel:d,maxHeadingLevel:h,...x}=e;const p=(0,r.L)(),j=null!=d?d:p.tableOfContents.minHeadingLevel,g=null!=h?h:p.tableOfContents.maxHeadingLevel,v=function(e){let{toc:n,minHeadingLevel:i,maxHeadingLevel:r}=e;return(0,t.useMemo)((()=>o({toc:s(n),minHeadingLevel:i,maxHeadingLevel:r})),[n,i,r])}({toc:n,minHeadingLevel:j,maxHeadingLevel:g});return a((0,t.useMemo)((()=>{if(l&&c)return{linkClassName:l,linkActiveClassName:c,minHeadingLevel:j,maxHeadingLevel:g}}),[l,c,j,g])),(0,u.jsx)(m,{toc:v,className:i,linkClassName:l,...x})}},3762:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>d,contentTitle:()=>l,default:()=>u,frontMatter:()=>o,metadata:()=>c,toc:()=>a});var t=i(5893),r=i(1151),s=i(2063);const o={id:"migration-v2",title:"Migration to 2.0"},l=void 0,c={id:"migration-v2",title:"Migration to 2.0",description:"This guide describes steps necessary to migrate from React Native Testing Library v1.x to v2.0.",source:"@site/docs/MigrationV2.md",sourceDirName:".",slug:"/migration-v2",permalink:"/react-native-testing-library/docs/migration-v2",draft:!1,unlisted:!1,editUrl:"https://github.com/callstack/react-native-testing-library/blob/main/website/docs/MigrationV2.md",tags:[],version:"current",frontMatter:{id:"migration-v2",title:"Migration to 2.0"},sidebar:"docs",previous:{title:"Migration to 7.0",permalink:"/react-native-testing-library/docs/migration-v7"}},d={},a=[{value:"Dropping Node 8",id:"dropping-node-8",level:2},{value:"Auto Cleanup",id:"auto-cleanup",level:2},{value:"WaitFor API changes",id:"waitfor-api-changes",level:2},{value:"Removed global debug function",id:"removed-global-debug-function",level:2},{value:"Removed global shallow function",id:"removed-global-shallow-function",level:2},{value:"Removed functions",id:"removed-functions",level:2},{value:"Some ByTestId queries behavior changes",id:"some-bytestid-queries-behavior-changes",level:2},{value:"Deprecated flushMicrotasksQueue",id:"deprecated-flushmicrotasksqueue",level:2}];function h(e){const n={a:"a",admonition:"admonition",code:"code",h2:"h2",li:"li",p:"p",pre:"pre",ul:"ul",...(0,r.a)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)(n.p,{children:["This guide describes steps necessary to migrate from React Native Testing Library ",(0,t.jsx)(n.code,{children:"v1.x"})," to ",(0,t.jsx)(n.code,{children:"v2.0"}),"."]}),"\n","\n","\n",(0,t.jsx)(s.Z,{toc:a}),"\n",(0,t.jsx)(n.h2,{id:"dropping-node-8",children:"Dropping Node 8"}),"\n",(0,t.jsx)(n.p,{children:"Node 8 reached its EOL more than 5 months ago, so it's about time to target the library to Node 10. If you used lower version, you'll have to upgrade to v10, but we recommend using the latest LTS version."}),"\n",(0,t.jsx)(n.h2,{id:"auto-cleanup",children:"Auto Cleanup"}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"cleanup()"})," function is now called automatically after every test if your testing framework supports ",(0,t.jsx)(n.code,{children:"afterEach"})," hook (like Jest, Mocha, and Jasmine)."]}),"\n",(0,t.jsxs)(n.p,{children:["You should be able to remove all ",(0,t.jsx)(n.code,{children:"afterEach(cleanup)"})," calls in your code."]}),"\n",(0,t.jsxs)(n.p,{children:["This change might break your code, if you tests are not isolated, i.e. you call ",(0,t.jsx)(n.code,{children:"render"})," outside ",(0,t.jsx)(n.code,{children:"test"})," block. Generally, you should ",(0,t.jsx)(n.a,{href:"https://kentcdodds.com/blog/test-isolation-with-react",children:"keep your tests isolated"}),". But if you can't or don't want to do this right away you can prevent this behavior using any of the following ways:"]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:["by importing ",(0,t.jsx)(n.code,{children:"'react-native-testing-library/pure'"})," instead of ",(0,t.jsx)(n.code,{children:"'react-native-testing-library'"})]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:["by importing ",(0,t.jsx)(n.code,{children:"'react-native-testing-library/dont-cleanup-after-each'"})," before importing ",(0,t.jsx)(n.code,{children:"'react-native-testing-library'"}),". You can do it in a global way by using Jest's ",(0,t.jsx)(n.code,{children:"setupFiles"})," like this:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-json",children:'{\n "setupFiles": ["react-native-testing-library/dont-cleanup-after-each"];\n}\n'})}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:["by setting ",(0,t.jsx)(n.code,{children:"RNTL_SKIP_AUTO_CLEANUP"})," env variable to ",(0,t.jsx)(n.code,{children:"true"}),". You can do this with ",(0,t.jsx)(n.code,{children:"cross-evn"})," like this:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sh",children:"cross-env RNTL_SKIP_AUTO_CLEANUP=true jest\n"})}),"\n"]}),"\n"]}),"\n",(0,t.jsx)(n.h2,{id:"waitfor-api-changes",children:"WaitFor API changes"}),"\n",(0,t.jsxs)(n.p,{children:["We renamed ",(0,t.jsx)(n.code,{children:"waitForElement"})," function to ",(0,t.jsx)(n.code,{children:"waitFor"})," for consistency with React Testing Library. Additionally, the signature has slightly changed from:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-jsx",children:"export default function waitForElement(\n expectation: () => T,\n timeout?: number,\n interval?: number\n): Promise {}\n"})}),"\n",(0,t.jsx)(n.p,{children:"to:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-jsx",children:"export default function waitFor(\n expectation: () => T,\n options: {\n timeout?: number,\n interval?: number,\n }\n): Promise {}\n"})}),"\n",(0,t.jsx)(n.p,{children:"Both changes should improve code readibility."}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"waitFor"})," calls (and hence also ",(0,t.jsx)(n.code,{children:"findBy"})," queries) are now wrapped in ",(0,t.jsx)(n.code,{children:"act"})," by default, so that you should no longer need to use ",(0,t.jsx)(n.code,{children:"act"})," directly in your tests."]}),"\n",(0,t.jsx)(n.admonition,{type:"tip",children:(0,t.jsxs)(n.p,{children:["You can usually avoid ",(0,t.jsx)(n.code,{children:"waitFor"})," by a proper use of ",(0,t.jsx)(n.code,{children:"findBy"})," asynchronous queries. It will result in more streamlined testing experience."]})}),"\n",(0,t.jsxs)(n.h2,{id:"removed-global-debug-function",children:["Removed global ",(0,t.jsx)(n.code,{children:"debug"})," function"]}),"\n",(0,t.jsxs)(n.p,{children:["The ",(0,t.jsx)(n.code,{children:"debug()"})," method returned from ",(0,t.jsx)(n.code,{children:"render()"})," function is all you need. We removed the global export to avoid confusion."]}),"\n",(0,t.jsxs)(n.h2,{id:"removed-global-shallow-function",children:["Removed global ",(0,t.jsx)(n.code,{children:"shallow"})," function"]}),"\n",(0,t.jsx)(n.p,{children:"Shallow rendering React component is usually not a good idea, so we decided to remove the API. But, if you find it useful or need to support legacy tests, feel free to use this implementation:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-js",children:"import ShallowRenderer from 'react-test-renderer/shallow';\n\nexport function shallow(instance: ReactTestInstance | React.Element) {\n const renderer = new ShallowRenderer();\n renderer.render(React.createElement(instance.type, instance.props));\n\n return { output: renderer.getRenderOutput() };\n}\n"})}),"\n",(0,t.jsx)(n.h2,{id:"removed-functions",children:"Removed functions"}),"\n",(0,t.jsx)(n.p,{children:"Following query functions have been removed after being deprecated for more than a year now:"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.code,{children:"getByName"})}),"\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.code,{children:"getAllByName"})}),"\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.code,{children:"queryByName"})}),"\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.code,{children:"queryAllByName"})}),"\n"]}),"\n",(0,t.jsxs)(n.p,{children:["The ",(0,t.jsx)(n.code,{children:"*ByType"})," and ",(0,t.jsx)(n.code,{children:"*ByProps"})," queries has been prefixed with ",(0,t.jsx)(n.code,{children:"UNSAFE_"}),". These ",(0,t.jsx)(n.code,{children:"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:"]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"getByType"})," -> ",(0,t.jsx)(n.code,{children:"UNSAFE_getByType"})]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"getAllByType"})," -> ",(0,t.jsx)(n.code,{children:"UNSAFE_getAllByType"})]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"queryByType"})," -> ",(0,t.jsx)(n.code,{children:"UNSAFE_queryByType"})]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"queryAllByType"})," -> ",(0,t.jsx)(n.code,{children:"UNSAFE_queryAllByType"})]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"getByProps"})," -> ",(0,t.jsx)(n.code,{children:"UNSAFE_getByProps"})]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"getAllByProps"})," -> ",(0,t.jsx)(n.code,{children:"UNSAFE_getAllByProps"})]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"queryByProps"})," -> ",(0,t.jsx)(n.code,{children:"UNSAFE_queryByProps"})]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"queryAllByProps"})," -> ",(0,t.jsx)(n.code,{children:"UNSAFE_queryAllByProps"})]}),"\n"]}),"\n",(0,t.jsxs)(n.h2,{id:"some-bytestid-queries-behavior-changes",children:["Some ",(0,t.jsx)(n.code,{children:"ByTestId"})," queries behavior changes"]}),"\n",(0,t.jsxs)(n.p,{children:["In version ",(0,t.jsx)(n.code,{children:"1.x"})," the ",(0,t.jsx)(n.code,{children:"getByTestId"})," and ",(0,t.jsx)(n.code,{children:"queryByTestId"})," queries could return non-native instances. This was a serious bug. Other query functions like ",(0,t.jsx)(n.code,{children:"getAllByTestId"}),", ",(0,t.jsx)(n.code,{children:"queryAllByTestId"}),", ",(0,t.jsx)(n.code,{children:"findByTestId"})," and ",(0,t.jsx)(n.code,{children:"findAllByTestId"})," didn't have this issue. These correctly returned only native components instances (e.g. ",(0,t.jsx)(n.code,{children:"View"}),", ",(0,t.jsx)(n.code,{children:"Text"}),", etc) that got the ",(0,t.jsx)(n.code,{children:"testID"}),"."]}),"\n",(0,t.jsx)(n.p,{children:"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:"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["pass the ",(0,t.jsx)(n.code,{children:"testID"})," prop down so it can reach a native component, like ",(0,t.jsx)(n.code,{children:"View"})," or ",(0,t.jsx)(n.code,{children:"Text"})]}),"\n",(0,t.jsxs)(n.li,{children:["replace ",(0,t.jsx)(n.code,{children:"testID"})," with proper ",(0,t.jsx)(n.code,{children:"accessibilityHint"})," or ",(0,t.jsx)(n.code,{children:"accessibilityLabel"})," if it benefits the user"]}),"\n",(0,t.jsxs)(n.li,{children:["use safe queries like ",(0,t.jsx)(n.code,{children:"*ByText"})," or ",(0,t.jsx)(n.code,{children:"*ByA11yHint"})]}),"\n"]}),"\n",(0,t.jsxs)(n.h2,{id:"deprecated-flushmicrotasksqueue",children:["Deprecated ",(0,t.jsx)(n.code,{children:"flushMicrotasksQueue"})]}),"\n",(0,t.jsxs)(n.p,{children:["We have deprecated ",(0,t.jsx)(n.code,{children:"flushMicrotasksQueue"})," and plan to remove it in the next major. We have better alternatives available for helping you write async tests \u2013 ",(0,t.jsx)(n.code,{children:"findBy"})," async queries and ",(0,t.jsx)(n.code,{children:"waitFor"})," helper."]}),"\n",(0,t.jsx)(n.p,{children:"If you can't or don't want to migrate your tests, don't worry. You can use the same implementation we have today:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-js",children:"function flushMicrotasksQueue() {\n return new Promise((resolve) => setImmediate(resolve));\n}\n"})})]})}function u(e={}){const{wrapper:n}={...(0,r.a)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(h,{...e})}):h(e)}},1151:(e,n,i)=>{i.d(n,{Z:()=>l,a:()=>o});var t=i(7294);const r={},s=t.createContext(r);function o(e){const n=t.useContext(s);return t.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function l(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),t.createElement(s.Provider,{value:n},e.children)}}}]); \ No newline at end of file +"use strict";(self.webpackChunkreact_native_testing_library_website=self.webpackChunkreact_native_testing_library_website||[]).push([[494],{2063:(e,n,i)=>{i.d(n,{Z:()=>o});i(7294);var t=i(1351);const r={tableOfContentsInline:"tableOfContentsInline_prmo"};var s=i(5893);function o(e){let{toc:n,minHeadingLevel:i,maxHeadingLevel:o}=e;return(0,s.jsx)("div",{className:r.tableOfContentsInline,children:(0,s.jsx)(t.Z,{toc:n,minHeadingLevel:i,maxHeadingLevel:o,className:"table-of-contents",linkClassName:null})})}},1351:(e,n,i)=>{i.d(n,{Z:()=>p});var t=i(7294),r=i(6793);function s(e){const n=e.map((e=>({...e,parentIndex:-1,children:[]}))),i=Array(7).fill(-1);n.forEach(((e,n)=>{const t=i.slice(2,e.level);e.parentIndex=Math.max(...t),i[e.level]=n}));const t=[];return n.forEach((e=>{const{parentIndex:i,...r}=e;i>=0?n[i].children.push(r):t.push(r)})),t}function o(e){let{toc:n,minHeadingLevel:i,maxHeadingLevel:t}=e;return n.flatMap((e=>{const n=o({toc:e.children,minHeadingLevel:i,maxHeadingLevel:t});return function(e){return e.level>=i&&e.level<=t}(e)?[{...e,children:n}]:n}))}function l(e){const n=e.getBoundingClientRect();return n.top===n.bottom?l(e.parentNode):n}function c(e,n){var i;let{anchorTopOffset:t}=n;const r=e.find((e=>l(e).top>=t));if(r){var s;return function(e){return e.top>0&&e.bottom{e.current=n?0:document.querySelector(".navbar").clientHeight}),[n]),e}function a(e){const n=(0,t.useRef)(void 0),i=d();(0,t.useEffect)((()=>{if(!e)return()=>{};const{linkClassName:t,linkActiveClassName:r,minHeadingLevel:s,maxHeadingLevel:o}=e;function l(){const e=function(e){return Array.from(document.getElementsByClassName(e))}(t),l=function(e){let{minHeadingLevel:n,maxHeadingLevel:i}=e;const t=[];for(let r=n;r<=i;r+=1)t.push("h"+r+".anchor");return Array.from(document.querySelectorAll(t.join()))}({minHeadingLevel:s,maxHeadingLevel:o}),d=c(l,{anchorTopOffset:i.current}),a=e.find((e=>d&&d.id===function(e){return decodeURIComponent(e.href.substring(e.href.indexOf("#")+1))}(e)));e.forEach((e=>{!function(e,i){i?(n.current&&n.current!==e&&n.current.classList.remove(r),e.classList.add(r),n.current=e):e.classList.remove(r)}(e,e===a)}))}return document.addEventListener("scroll",l),document.addEventListener("resize",l),l(),()=>{document.removeEventListener("scroll",l),document.removeEventListener("resize",l)}}),[e,i])}var h=i(8746),u=i(5893);function x(e){let{toc:n,className:i,linkClassName:t,isChild:r}=e;return n.length?(0,u.jsx)("ul",{className:r?void 0:i,children:n.map((e=>(0,u.jsxs)("li",{children:[(0,u.jsx)(h.Z,{to:"#"+e.id,className:null!=t?t:void 0,dangerouslySetInnerHTML:{__html:e.value}}),(0,u.jsx)(x,{isChild:!0,toc:e.children,className:i,linkClassName:t})]},e.id)))}):null}const m=t.memo(x);function p(e){let{toc:n,className:i="table-of-contents table-of-contents__left-border",linkClassName:l="table-of-contents__link",linkActiveClassName:c,minHeadingLevel:d,maxHeadingLevel:h,...x}=e;const p=(0,r.L)(),j=null!=d?d:p.tableOfContents.minHeadingLevel,g=null!=h?h:p.tableOfContents.maxHeadingLevel,v=function(e){let{toc:n,minHeadingLevel:i,maxHeadingLevel:r}=e;return(0,t.useMemo)((()=>o({toc:s(n),minHeadingLevel:i,maxHeadingLevel:r})),[n,i,r])}({toc:n,minHeadingLevel:j,maxHeadingLevel:g});return a((0,t.useMemo)((()=>{if(l&&c)return{linkClassName:l,linkActiveClassName:c,minHeadingLevel:j,maxHeadingLevel:g}}),[l,c,j,g])),(0,u.jsx)(m,{toc:v,className:i,linkClassName:l,...x})}},3762:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>d,contentTitle:()=>l,default:()=>u,frontMatter:()=>o,metadata:()=>c,toc:()=>a});var t=i(5893),r=i(1151),s=i(2063);const o={id:"migration-v2",title:"Migration to 2.0"},l=void 0,c={id:"migration-v2",title:"Migration to 2.0",description:"This guide describes steps necessary to migrate from React Native Testing Library v1.x to v2.0.",source:"@site/docs/MigrationV2.md",sourceDirName:".",slug:"/migration-v2",permalink:"/react-native-testing-library/docs/migration-v2",draft:!1,unlisted:!1,editUrl:"https://github.com/callstack/react-native-testing-library/blob/main/website/docs/MigrationV2.md",tags:[],version:"current",frontMatter:{id:"migration-v2",title:"Migration to 2.0"},sidebar:"docs",previous:{title:"Migration to 7.0",permalink:"/react-native-testing-library/docs/migration-v7"}},d={},a=[{value:"Dropping Node 8",id:"dropping-node-8",level:2},{value:"Auto Cleanup",id:"auto-cleanup",level:2},{value:"WaitFor API changes",id:"waitfor-api-changes",level:2},{value:"Removed global debug function",id:"removed-global-debug-function",level:2},{value:"Removed global shallow function",id:"removed-global-shallow-function",level:2},{value:"Removed functions",id:"removed-functions",level:2},{value:"Some ByTestId queries behavior changes",id:"some-bytestid-queries-behavior-changes",level:2},{value:"Deprecated flushMicrotasksQueue",id:"deprecated-flushmicrotasksqueue",level:2}];function h(e){const n={a:"a",admonition:"admonition",code:"code",h2:"h2",li:"li",p:"p",pre:"pre",ul:"ul",...(0,r.a)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)(n.p,{children:["This guide describes steps necessary to migrate from React Native Testing Library ",(0,t.jsx)(n.code,{children:"v1.x"})," to ",(0,t.jsx)(n.code,{children:"v2.0"}),"."]}),"\n","\n","\n",(0,t.jsx)(s.Z,{toc:a}),"\n",(0,t.jsx)(n.h2,{id:"dropping-node-8",children:"Dropping Node 8"}),"\n",(0,t.jsx)(n.p,{children:"Node 8 reached its EOL more than 5 months ago, so it's about time to target the library to Node 10. If you used lower version, you'll have to upgrade to v10, but we recommend using the latest LTS version."}),"\n",(0,t.jsx)(n.h2,{id:"auto-cleanup",children:"Auto Cleanup"}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"cleanup()"})," function is now called automatically after every test if your testing framework supports ",(0,t.jsx)(n.code,{children:"afterEach"})," hook (like Jest, Mocha, and Jasmine)."]}),"\n",(0,t.jsxs)(n.p,{children:["You should be able to remove all ",(0,t.jsx)(n.code,{children:"afterEach(cleanup)"})," calls in your code."]}),"\n",(0,t.jsxs)(n.p,{children:["This change might break your code, if you tests are not isolated, i.e. you call ",(0,t.jsx)(n.code,{children:"render"})," outside ",(0,t.jsx)(n.code,{children:"test"})," block. Generally, you should ",(0,t.jsx)(n.a,{href:"https://kentcdodds.com/blog/test-isolation-with-react",children:"keep your tests isolated"}),". But if you can't or don't want to do this right away you can prevent this behavior using any of the following ways:"]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:["by importing ",(0,t.jsx)(n.code,{children:"'react-native-testing-library/pure'"})," instead of ",(0,t.jsx)(n.code,{children:"'react-native-testing-library'"})]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:["by importing ",(0,t.jsx)(n.code,{children:"'react-native-testing-library/dont-cleanup-after-each'"})," before importing ",(0,t.jsx)(n.code,{children:"'react-native-testing-library'"}),". You can do it in a global way by using Jest's ",(0,t.jsx)(n.code,{children:"setupFiles"})," like this:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-json",children:'{\n "setupFiles": ["react-native-testing-library/dont-cleanup-after-each"];\n}\n'})}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:["by setting ",(0,t.jsx)(n.code,{children:"RNTL_SKIP_AUTO_CLEANUP"})," env variable to ",(0,t.jsx)(n.code,{children:"true"}),". You can do this with ",(0,t.jsx)(n.code,{children:"cross-evn"})," like this:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sh",children:"cross-env RNTL_SKIP_AUTO_CLEANUP=true jest\n"})}),"\n"]}),"\n"]}),"\n",(0,t.jsx)(n.h2,{id:"waitfor-api-changes",children:"WaitFor API changes"}),"\n",(0,t.jsxs)(n.p,{children:["We renamed ",(0,t.jsx)(n.code,{children:"waitForElement"})," function to ",(0,t.jsx)(n.code,{children:"waitFor"})," for consistency with React Testing Library. Additionally, the signature has slightly changed from:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-jsx",children:"export default function waitForElement(\n expectation: () => T,\n timeout?: number,\n interval?: number,\n): Promise {}\n"})}),"\n",(0,t.jsx)(n.p,{children:"to:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-jsx",children:"export default function waitFor(\n expectation: () => T,\n options: {\n timeout?: number,\n interval?: number,\n },\n): Promise {}\n"})}),"\n",(0,t.jsx)(n.p,{children:"Both changes should improve code readibility."}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"waitFor"})," calls (and hence also ",(0,t.jsx)(n.code,{children:"findBy"})," queries) are now wrapped in ",(0,t.jsx)(n.code,{children:"act"})," by default, so that you should no longer need to use ",(0,t.jsx)(n.code,{children:"act"})," directly in your tests."]}),"\n",(0,t.jsx)(n.admonition,{type:"tip",children:(0,t.jsxs)(n.p,{children:["You can usually avoid ",(0,t.jsx)(n.code,{children:"waitFor"})," by a proper use of ",(0,t.jsx)(n.code,{children:"findBy"})," asynchronous queries. It will result in more streamlined testing experience."]})}),"\n",(0,t.jsxs)(n.h2,{id:"removed-global-debug-function",children:["Removed global ",(0,t.jsx)(n.code,{children:"debug"})," function"]}),"\n",(0,t.jsxs)(n.p,{children:["The ",(0,t.jsx)(n.code,{children:"debug()"})," method returned from ",(0,t.jsx)(n.code,{children:"render()"})," function is all you need. We removed the global export to avoid confusion."]}),"\n",(0,t.jsxs)(n.h2,{id:"removed-global-shallow-function",children:["Removed global ",(0,t.jsx)(n.code,{children:"shallow"})," function"]}),"\n",(0,t.jsx)(n.p,{children:"Shallow rendering React component is usually not a good idea, so we decided to remove the API. But, if you find it useful or need to support legacy tests, feel free to use this implementation:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-js",children:"import ShallowRenderer from 'react-test-renderer/shallow';\n\nexport function shallow(instance: ReactTestInstance | React.Element) {\n const renderer = new ShallowRenderer();\n renderer.render(React.createElement(instance.type, instance.props));\n\n return { output: renderer.getRenderOutput() };\n}\n"})}),"\n",(0,t.jsx)(n.h2,{id:"removed-functions",children:"Removed functions"}),"\n",(0,t.jsx)(n.p,{children:"Following query functions have been removed after being deprecated for more than a year now:"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.code,{children:"getByName"})}),"\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.code,{children:"getAllByName"})}),"\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.code,{children:"queryByName"})}),"\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.code,{children:"queryAllByName"})}),"\n"]}),"\n",(0,t.jsxs)(n.p,{children:["The ",(0,t.jsx)(n.code,{children:"*ByType"})," and ",(0,t.jsx)(n.code,{children:"*ByProps"})," queries has been prefixed with ",(0,t.jsx)(n.code,{children:"UNSAFE_"}),". These ",(0,t.jsx)(n.code,{children:"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:"]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"getByType"})," -> ",(0,t.jsx)(n.code,{children:"UNSAFE_getByType"})]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"getAllByType"})," -> ",(0,t.jsx)(n.code,{children:"UNSAFE_getAllByType"})]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"queryByType"})," -> ",(0,t.jsx)(n.code,{children:"UNSAFE_queryByType"})]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"queryAllByType"})," -> ",(0,t.jsx)(n.code,{children:"UNSAFE_queryAllByType"})]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"getByProps"})," -> ",(0,t.jsx)(n.code,{children:"UNSAFE_getByProps"})]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"getAllByProps"})," -> ",(0,t.jsx)(n.code,{children:"UNSAFE_getAllByProps"})]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"queryByProps"})," -> ",(0,t.jsx)(n.code,{children:"UNSAFE_queryByProps"})]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"queryAllByProps"})," -> ",(0,t.jsx)(n.code,{children:"UNSAFE_queryAllByProps"})]}),"\n"]}),"\n",(0,t.jsxs)(n.h2,{id:"some-bytestid-queries-behavior-changes",children:["Some ",(0,t.jsx)(n.code,{children:"ByTestId"})," queries behavior changes"]}),"\n",(0,t.jsxs)(n.p,{children:["In version ",(0,t.jsx)(n.code,{children:"1.x"})," the ",(0,t.jsx)(n.code,{children:"getByTestId"})," and ",(0,t.jsx)(n.code,{children:"queryByTestId"})," queries could return non-native instances. This was a serious bug. Other query functions like ",(0,t.jsx)(n.code,{children:"getAllByTestId"}),", ",(0,t.jsx)(n.code,{children:"queryAllByTestId"}),", ",(0,t.jsx)(n.code,{children:"findByTestId"})," and ",(0,t.jsx)(n.code,{children:"findAllByTestId"})," didn't have this issue. These correctly returned only native components instances (e.g. ",(0,t.jsx)(n.code,{children:"View"}),", ",(0,t.jsx)(n.code,{children:"Text"}),", etc) that got the ",(0,t.jsx)(n.code,{children:"testID"}),"."]}),"\n",(0,t.jsx)(n.p,{children:"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:"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["pass the ",(0,t.jsx)(n.code,{children:"testID"})," prop down so it can reach a native component, like ",(0,t.jsx)(n.code,{children:"View"})," or ",(0,t.jsx)(n.code,{children:"Text"})]}),"\n",(0,t.jsxs)(n.li,{children:["replace ",(0,t.jsx)(n.code,{children:"testID"})," with proper ",(0,t.jsx)(n.code,{children:"accessibilityHint"})," or ",(0,t.jsx)(n.code,{children:"accessibilityLabel"})," if it benefits the user"]}),"\n",(0,t.jsxs)(n.li,{children:["use safe queries like ",(0,t.jsx)(n.code,{children:"*ByText"})," or ",(0,t.jsx)(n.code,{children:"*ByA11yHint"})]}),"\n"]}),"\n",(0,t.jsxs)(n.h2,{id:"deprecated-flushmicrotasksqueue",children:["Deprecated ",(0,t.jsx)(n.code,{children:"flushMicrotasksQueue"})]}),"\n",(0,t.jsxs)(n.p,{children:["We have deprecated ",(0,t.jsx)(n.code,{children:"flushMicrotasksQueue"})," and plan to remove it in the next major. We have better alternatives available for helping you write async tests \u2013 ",(0,t.jsx)(n.code,{children:"findBy"})," async queries and ",(0,t.jsx)(n.code,{children:"waitFor"})," helper."]}),"\n",(0,t.jsx)(n.p,{children:"If you can't or don't want to migrate your tests, don't worry. You can use the same implementation we have today:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-js",children:"function flushMicrotasksQueue() {\n return new Promise((resolve) => setImmediate(resolve));\n}\n"})})]})}function u(e={}){const{wrapper:n}={...(0,r.a)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(h,{...e})}):h(e)}},1151:(e,n,i)=>{i.d(n,{Z:()=>l,a:()=>o});var t=i(7294);const r={},s=t.createContext(r);function o(e){const n=t.useContext(s);return t.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function l(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),t.createElement(s.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/77ba9e12.7c7fa4d8.js b/assets/js/77ba9e12.319083fc.js similarity index 58% rename from assets/js/77ba9e12.7c7fa4d8.js rename to assets/js/77ba9e12.319083fc.js index 30b650fe..ea324439 100644 --- a/assets/js/77ba9e12.7c7fa4d8.js +++ b/assets/js/77ba9e12.319083fc.js @@ -1 +1 @@ -"use strict";(self.webpackChunkreact_native_testing_library_website=self.webpackChunkreact_native_testing_library_website||[]).push([[625],{7834:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>a,contentTitle:()=>r,default:()=>p,frontMatter:()=>i,metadata:()=>d,toc:()=>c});var o=n(5893),s=n(1151);const i={id:"redux-integration",title:"Redux Integration"},r=void 0,d={id:"redux-integration",title:"Redux Integration",description:"This examples has not been updated for a long time and not showcase current recommended testing practices. We plan to update this document soon.",source:"@site/docs/ReduxIntegration.md",sourceDirName:".",slug:"/redux-integration",permalink:"/react-native-testing-library/docs/redux-integration",draft:!1,unlisted:!1,editUrl:"https://github.com/callstack/react-native-testing-library/blob/main/website/docs/ReduxIntegration.md",tags:[],version:"current",frontMatter:{id:"redux-integration",title:"Redux Integration"}},a={},c=[{value:"Setting up",id:"setting-up",level:2},{value:"Test cases",id:"test-cases",level:2},{value:"Running tests",id:"running-tests",level:2}];function l(e){const t={a:"a",admonition:"admonition",code:"code",h2:"h2",p:"p",pre:"pre",...(0,s.a)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(t.admonition,{type:"caution",children:(0,o.jsx)(t.p,{children:"This examples has not been updated for a long time and not showcase current recommended testing practices. We plan to update this document soon."})}),"\n",(0,o.jsx)(t.p,{children:"This section deals with testing RN applications developed with Redux. We will be developing a simple TODO application capable of adding and removing an item. Once included, the timestamp is included."}),"\n",(0,o.jsx)(t.h2,{id:"setting-up",children:"Setting up"}),"\n",(0,o.jsxs)(t.p,{children:["An example of setting up can be found ",(0,o.jsx)(t.a,{href:"https://github.com/callstack/react-native-testing-library/tree/main/examples/redux",children:"here"}),"."]}),"\n",(0,o.jsx)(t.h2,{id:"test-cases",children:"Test cases"}),"\n",(0,o.jsxs)(t.p,{children:["Our test is on the components that either dispatch actions on the redux store or read some data from the redux store. This means we will test ",(0,o.jsx)(t.code,{children:"./components/AddTodo.js"})," and ",(0,o.jsx)(t.code,{children:"./components/TodoList.js"}),". Thus we will create ",(0,o.jsx)(t.code,{children:"./components/AddTodo.test.js"})," and ",(0,o.jsx)(t.code,{children:"./components/TodoList.test.js"})]}),"\n",(0,o.jsxs)(t.p,{children:["For ",(0,o.jsx)(t.code,{children:"./components/AddTodo.test.js"})]}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-jsx",children:"import * as React from 'react';\nimport { Provider } from 'react-redux';\nimport { render, screen, fireEvent } from '@testing-library/react-native';\nimport configureStore from '../store';\nimport AddTodo from './AddTodo';\n\ndescribe('AddTodo component test', () => {\n test('adds a new TODO when the button is pressed', () => {\n const store = configureStore();\n\n const component = (\n \n \n \n );\n\n render(component);\n\n // There is a TextInput.\n // https://github.com/callstack/react-native-testing-library/blob/ae3d4af370487e1e8fedd8219f77225690aefc59/examples/redux/components/AddTodo.js#L24\n const input = screen.getByPlaceholderText(/repository/i);\n expect(input).toBeOnTheScreen();\n\n const textToEnter = 'This is a random element';\n fireEvent.changeText(input, textToEnter);\n fireEvent.press(screen.getByText('Submit form'));\n\n const todosState = store.getState().todos;\n\n expect(todosState.length).toEqual(1);\n\n expect(todosState).toEqual(\n expect.arrayContaining([\n expect.objectContaining({\n id: 1,\n text: textToEnter,\n date: expect.any(Date),\n }),\n ])\n );\n });\n});\n"})}),"\n",(0,o.jsxs)(t.p,{children:["For ",(0,o.jsx)(t.code,{children:"./components/TodoList.test.js"})]}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-jsx",children:"import * as React from 'react';\nimport { Provider } from 'react-redux';\nimport { render, screen, fireEvent } from '@testing-library/react-native';\nimport configureStore from '../store';\nimport TodoList from './TodoList';\n\ndescribe('TodoList component test', () => {\n test('it should execute with a store with 4 elements', () => {\n const initialState = {\n todos: [\n { id: 1, text: 'Sing something', date: new Date() },\n { id: 2, text: 'Dance something', date: new Date() },\n { id: 3, text: 'Sleep something', date: new Date() },\n { id: 4, text: 'Sleep something', date: new Date() },\n ],\n };\n const store = configureStore(initialState);\n\n const component = (\n \n \n \n );\n\n render(component);\n const todoElems = screen.getAllByText(/something/i);\n\n expect(todoElems.length).toEqual(4);\n });\n\n test('should execute with 2 elements and end up with 1 after delete', () => {\n const initialState = {\n todos: [\n { id: 1, text: 'Sing something', date: new Date() },\n { id: 2, text: 'Dance something', date: new Date() },\n ],\n };\n const store = configureStore(initialState);\n\n const component = (\n \n \n \n );\n\n render(component);\n const todoElems = screen.getAllByText(/something/i);\n\n expect(todoElems.length).toBe(2);\n\n const buttons = screen.getAllByText('Delete');\n expect(buttons.length).toBe(2);\n\n fireEvent.press(buttons[0]);\n expect(screen.getAllByText('Delete').length).toBe(1);\n });\n});\n"})}),"\n",(0,o.jsx)(t.h2,{id:"running-tests",children:"Running tests"}),"\n",(0,o.jsx)(t.p,{children:"To run the tests, place a test script inside your package.json"}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-json",children:'{\n "scripts": {\n "test": "jest"\n }\n}\n'})}),"\n",(0,o.jsx)(t.p,{children:"And run the test script with npm test or yarn test."})]})}function p(e={}){const{wrapper:t}={...(0,s.a)(),...e.components};return t?(0,o.jsx)(t,{...e,children:(0,o.jsx)(l,{...e})}):l(e)}},1151:(e,t,n)=>{n.d(t,{Z:()=>d,a:()=>r});var o=n(7294);const s={},i=o.createContext(s);function r(e){const t=o.useContext(i);return o.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function d(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:r(e.components),o.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file +"use strict";(self.webpackChunkreact_native_testing_library_website=self.webpackChunkreact_native_testing_library_website||[]).push([[625],{7834:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>a,contentTitle:()=>r,default:()=>p,frontMatter:()=>i,metadata:()=>d,toc:()=>c});var o=n(5893),s=n(1151);const i={id:"redux-integration",title:"Redux Integration"},r=void 0,d={id:"redux-integration",title:"Redux Integration",description:"This examples has not been updated for a long time and not showcase current recommended testing practices. We plan to update this document soon.",source:"@site/docs/ReduxIntegration.md",sourceDirName:".",slug:"/redux-integration",permalink:"/react-native-testing-library/docs/redux-integration",draft:!1,unlisted:!1,editUrl:"https://github.com/callstack/react-native-testing-library/blob/main/website/docs/ReduxIntegration.md",tags:[],version:"current",frontMatter:{id:"redux-integration",title:"Redux Integration"}},a={},c=[{value:"Setting up",id:"setting-up",level:2},{value:"Test cases",id:"test-cases",level:2},{value:"Running tests",id:"running-tests",level:2}];function l(e){const t={a:"a",admonition:"admonition",code:"code",h2:"h2",p:"p",pre:"pre",...(0,s.a)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(t.admonition,{type:"caution",children:(0,o.jsx)(t.p,{children:"This examples has not been updated for a long time and not showcase current recommended testing practices. We plan to update this document soon."})}),"\n",(0,o.jsx)(t.p,{children:"This section deals with testing RN applications developed with Redux. We will be developing a simple TODO application capable of adding and removing an item. Once included, the timestamp is included."}),"\n",(0,o.jsx)(t.h2,{id:"setting-up",children:"Setting up"}),"\n",(0,o.jsxs)(t.p,{children:["An example of setting up can be found ",(0,o.jsx)(t.a,{href:"https://github.com/callstack/react-native-testing-library/tree/main/examples/redux",children:"here"}),"."]}),"\n",(0,o.jsx)(t.h2,{id:"test-cases",children:"Test cases"}),"\n",(0,o.jsxs)(t.p,{children:["Our test is on the components that either dispatch actions on the redux store or read some data from the redux store. This means we will test ",(0,o.jsx)(t.code,{children:"./components/AddTodo.js"})," and ",(0,o.jsx)(t.code,{children:"./components/TodoList.js"}),". Thus we will create ",(0,o.jsx)(t.code,{children:"./components/AddTodo.test.js"})," and ",(0,o.jsx)(t.code,{children:"./components/TodoList.test.js"})]}),"\n",(0,o.jsxs)(t.p,{children:["For ",(0,o.jsx)(t.code,{children:"./components/AddTodo.test.js"})]}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-jsx",children:"import * as React from 'react';\nimport { Provider } from 'react-redux';\nimport { render, screen, fireEvent } from '@testing-library/react-native';\nimport configureStore from '../store';\nimport AddTodo from './AddTodo';\n\ndescribe('AddTodo component test', () => {\n test('adds a new TODO when the button is pressed', () => {\n const store = configureStore();\n\n const component = (\n \n \n \n );\n\n render(component);\n\n // There is a TextInput.\n // https://github.com/callstack/react-native-testing-library/blob/ae3d4af370487e1e8fedd8219f77225690aefc59/examples/redux/components/AddTodo.js#L24\n const input = screen.getByPlaceholderText(/repository/i);\n expect(input).toBeOnTheScreen();\n\n const textToEnter = 'This is a random element';\n fireEvent.changeText(input, textToEnter);\n fireEvent.press(screen.getByText('Submit form'));\n\n const todosState = store.getState().todos;\n\n expect(todosState.length).toEqual(1);\n\n expect(todosState).toEqual(\n expect.arrayContaining([\n expect.objectContaining({\n id: 1,\n text: textToEnter,\n date: expect.any(Date),\n }),\n ]),\n );\n });\n});\n"})}),"\n",(0,o.jsxs)(t.p,{children:["For ",(0,o.jsx)(t.code,{children:"./components/TodoList.test.js"})]}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-jsx",children:"import * as React from 'react';\nimport { Provider } from 'react-redux';\nimport { render, screen, fireEvent } from '@testing-library/react-native';\nimport configureStore from '../store';\nimport TodoList from './TodoList';\n\ndescribe('TodoList component test', () => {\n test('it should execute with a store with 4 elements', () => {\n const initialState = {\n todos: [\n { id: 1, text: 'Sing something', date: new Date() },\n { id: 2, text: 'Dance something', date: new Date() },\n { id: 3, text: 'Sleep something', date: new Date() },\n { id: 4, text: 'Sleep something', date: new Date() },\n ],\n };\n const store = configureStore(initialState);\n\n const component = (\n \n \n \n );\n\n render(component);\n const todoElems = screen.getAllByText(/something/i);\n\n expect(todoElems.length).toEqual(4);\n });\n\n test('should execute with 2 elements and end up with 1 after delete', () => {\n const initialState = {\n todos: [\n { id: 1, text: 'Sing something', date: new Date() },\n { id: 2, text: 'Dance something', date: new Date() },\n ],\n };\n const store = configureStore(initialState);\n\n const component = (\n \n \n \n );\n\n render(component);\n const todoElems = screen.getAllByText(/something/i);\n\n expect(todoElems.length).toBe(2);\n\n const buttons = screen.getAllByText('Delete');\n expect(buttons.length).toBe(2);\n\n fireEvent.press(buttons[0]);\n expect(screen.getAllByText('Delete').length).toBe(1);\n });\n});\n"})}),"\n",(0,o.jsx)(t.h2,{id:"running-tests",children:"Running tests"}),"\n",(0,o.jsx)(t.p,{children:"To run the tests, place a test script inside your package.json"}),"\n",(0,o.jsx)(t.pre,{children:(0,o.jsx)(t.code,{className:"language-json",children:'{\n "scripts": {\n "test": "jest"\n }\n}\n'})}),"\n",(0,o.jsx)(t.p,{children:"And run the test script with npm test or yarn test."})]})}function p(e={}){const{wrapper:t}={...(0,s.a)(),...e.components};return t?(0,o.jsx)(t,{...e,children:(0,o.jsx)(l,{...e})}):l(e)}},1151:(e,t,n)=>{n.d(t,{Z:()=>d,a:()=>r});var o=n(7294);const s={},i=o.createContext(s);function r(e){const t=o.useContext(i);return o.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function d(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:r(e.components),o.createElement(i.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/7ad239b9.9d775967.js b/assets/js/7ad239b9.9d775967.js deleted file mode 100644 index 7ad07ef4..00000000 --- a/assets/js/7ad239b9.9d775967.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkreact_native_testing_library_website=self.webpackChunkreact_native_testing_library_website||[]).push([[430],{2063:(e,n,i)=>{i.d(n,{Z:()=>c});i(7294);var t=i(1351);const s={tableOfContentsInline:"tableOfContentsInline_prmo"};var l=i(5893);function c(e){let{toc:n,minHeadingLevel:i,maxHeadingLevel:c}=e;return(0,l.jsx)("div",{className:s.tableOfContentsInline,children:(0,l.jsx)(t.Z,{toc:n,minHeadingLevel:i,maxHeadingLevel:c,className:"table-of-contents",linkClassName:null})})}},1351:(e,n,i)=>{i.d(n,{Z:()=>j});var t=i(7294),s=i(6793);function l(e){const n=e.map((e=>({...e,parentIndex:-1,children:[]}))),i=Array(7).fill(-1);n.forEach(((e,n)=>{const t=i.slice(2,e.level);e.parentIndex=Math.max(...t),i[e.level]=n}));const t=[];return n.forEach((e=>{const{parentIndex:i,...s}=e;i>=0?n[i].children.push(s):t.push(s)})),t}function c(e){let{toc:n,minHeadingLevel:i,maxHeadingLevel:t}=e;return n.flatMap((e=>{const n=c({toc:e.children,minHeadingLevel:i,maxHeadingLevel:t});return function(e){return e.level>=i&&e.level<=t}(e)?[{...e,children:n}]:n}))}function r(e){const n=e.getBoundingClientRect();return n.top===n.bottom?r(e.parentNode):n}function a(e,n){var i;let{anchorTopOffset:t}=n;const s=e.find((e=>r(e).top>=t));if(s){var l;return function(e){return e.top>0&&e.bottom{e.current=n?0:document.querySelector(".navbar").clientHeight}),[n]),e}function o(e){const n=(0,t.useRef)(void 0),i=d();(0,t.useEffect)((()=>{if(!e)return()=>{};const{linkClassName:t,linkActiveClassName:s,minHeadingLevel:l,maxHeadingLevel:c}=e;function r(){const e=function(e){return Array.from(document.getElementsByClassName(e))}(t),r=function(e){let{minHeadingLevel:n,maxHeadingLevel:i}=e;const t=[];for(let s=n;s<=i;s+=1)t.push("h"+s+".anchor");return Array.from(document.querySelectorAll(t.join()))}({minHeadingLevel:l,maxHeadingLevel:c}),d=a(r,{anchorTopOffset:i.current}),o=e.find((e=>d&&d.id===function(e){return decodeURIComponent(e.href.substring(e.href.indexOf("#")+1))}(e)));e.forEach((e=>{!function(e,i){i?(n.current&&n.current!==e&&n.current.classList.remove(s),e.classList.add(s),n.current=e):e.classList.remove(s)}(e,e===o)}))}return document.addEventListener("scroll",r),document.addEventListener("resize",r),r(),()=>{document.removeEventListener("scroll",r),document.removeEventListener("resize",r)}}),[e,i])}var h=i(8746),x=i(5893);function u(e){let{toc:n,className:i,linkClassName:t,isChild:s}=e;return n.length?(0,x.jsx)("ul",{className:s?void 0:i,children:n.map((e=>(0,x.jsxs)("li",{children:[(0,x.jsx)(h.Z,{to:"#"+e.id,className:null!=t?t:void 0,dangerouslySetInnerHTML:{__html:e.value}}),(0,x.jsx)(u,{isChild:!0,toc:e.children,className:i,linkClassName:t})]},e.id)))}):null}const y=t.memo(u);function j(e){let{toc:n,className:i="table-of-contents table-of-contents__left-border",linkClassName:r="table-of-contents__link",linkActiveClassName:a,minHeadingLevel:d,maxHeadingLevel:h,...u}=e;const j=(0,s.L)(),m=null!=d?d:j.tableOfContents.minHeadingLevel,p=null!=h?h:j.tableOfContents.maxHeadingLevel,b=function(e){let{toc:n,minHeadingLevel:i,maxHeadingLevel:s}=e;return(0,t.useMemo)((()=>c({toc:l(n),minHeadingLevel:i,maxHeadingLevel:s})),[n,i,s])}({toc:n,minHeadingLevel:m,maxHeadingLevel:p});return o((0,t.useMemo)((()=>{if(r&&a)return{linkClassName:r,linkActiveClassName:a,minHeadingLevel:m,maxHeadingLevel:p}}),[r,a,m,p])),(0,x.jsx)(y,{toc:b,className:i,linkClassName:r,...u})}},4920:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>d,contentTitle:()=>r,default:()=>x,frontMatter:()=>c,metadata:()=>a,toc:()=>o});var t=i(5893),s=i(1151),l=i(2063);const c={id:"api-queries",title:"Queries"},r=void 0,a={id:"api-queries",title:"Queries",description:"Query Variants",source:"@site/docs/Queries.md",sourceDirName:".",slug:"/api-queries",permalink:"/react-native-testing-library/docs/api-queries",draft:!1,unlisted:!1,editUrl:"https://github.com/callstack/react-native-testing-library/blob/main/website/docs/Queries.md",tags:[],version:"current",frontMatter:{id:"api-queries",title:"Queries"},sidebar:"docs",previous:{title:"API",permalink:"/react-native-testing-library/docs/api"},next:{title:"User Event",permalink:"/react-native-testing-library/docs/user-event"}},d={},o=[{value:"Query Variants",id:"query-variants",level:2},{value:"getBy* queries",id:"get-by",level:3},{value:"getAllBy* queries",id:"get-all-by",level:3},{value:"queryBy* queries",id:"query-by",level:3},{value:"queryAllBy* queries",id:"query-all-by",level:3},{value:"findBy* queries",id:"find-by",level:3},{value:"findAllBy* queries",id:"find-all-by",level:3},{value:"Query Predicates",id:"query-predicates",level:2},{value:"ByRole",id:"by-role",level:3},{value:"Options",id:"by-role-options",level:4},{value:"ByText",id:"by-text",level:3},{value:"ByPlaceholderText",id:"by-placeholder-text",level:3},{value:"ByDisplayValue",id:"by-display-value",level:3},{value:"ByTestId",id:"by-test-id",level:3},{value:"ByLabelText",id:"by-label-text",level:3},{value:"ByHintText, ByA11yHint, ByAccessibilityHint",id:"by-hint-text",level:3},{value:"ByA11yState, ByAccessibilityState (deprecated)",id:"by-accessibility-state",level:3},{value:"Default state for: disabled, selected, and busy keys",id:"default-state-for-disabled-selected-and-busy-keys",level:4},{value:"Default state for: checked and expanded keys",id:"default-state-for-checked-and-expanded-keys",level:4},{value:"ByA11yValue, ByAccessibilityValue (deprecated)",id:"by-accessibility-value",level:3},{value:"Common options",id:"common-options",level:3},{value:"includeHiddenElements option",id:"includehiddenelements-option",level:4},{value:"TextMatch type",id:"textmatch-type",level:2},{value:"Examples",id:"examples",level:3},{value:"Options",id:"text-match-options",level:3},{value:"Precision",id:"precision",level:4},{value:"Normalization",id:"normalization",level:4},{value:"Normalization Examples",id:"normalization-examples",level:5},{value:"Legacy unit testing helpers",id:"legacy-unit-testing-helpers",level:2},{value:"UNSAFE_ByType",id:"unsafe_bytype",level:3},{value:"UNSAFE_ByProps",id:"unsafe_byprops",level:3}];function h(e){const n={a:"a",admonition:"admonition",blockquote:"blockquote",code:"code",em:"em",h2:"h2",h3:"h3",h4:"h4",h5:"h5",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.a)(),...e.components},{Details:i}=n;return i||function(e,n){throw new Error("Expected "+(n?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}("Details",!0),(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(l.Z,{toc:o}),"\n",(0,t.jsx)(n.h2,{id:"query-variants",children:"Query Variants"}),"\n",(0,t.jsxs)(n.blockquote,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"getBy*"})," queries are shown by default in the ",(0,t.jsx)(n.a,{href:"#queries",children:"query documentation"}),"\nbelow."]}),"\n"]}),"\n",(0,t.jsxs)(n.h3,{id:"get-by",children:[(0,t.jsx)(n.code,{children:"getBy*"})," queries"]}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"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. If you need to find more than one element, then use ",(0,t.jsx)(n.code,{children:"getAllBy"}),"."]}),"\n",(0,t.jsxs)(n.h3,{id:"get-all-by",children:[(0,t.jsx)(n.code,{children:"getAllBy*"})," queries"]}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"getAllBy*"})," queries return an array of all matching nodes for a query, and throw an error if no elements match."]}),"\n",(0,t.jsxs)(n.h3,{id:"query-by",children:[(0,t.jsx)(n.code,{children:"queryBy*"})," queries"]}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"queryBy*"})," queries return the first matching node for a query, and return ",(0,t.jsx)(n.code,{children:"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 ",(0,t.jsx)(n.code,{children:"queryAllBy"})," instead)."]}),"\n",(0,t.jsxs)(n.h3,{id:"query-all-by",children:[(0,t.jsx)(n.code,{children:"queryAllBy*"})," queries"]}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"queryAllBy*"})," queries return an array of all matching nodes for a query, and return an empty array (",(0,t.jsx)(n.code,{children:"[]"}),") when no elements match."]}),"\n",(0,t.jsxs)(n.h3,{id:"find-by",children:[(0,t.jsx)(n.code,{children:"findBy*"})," queries"]}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"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 1000 ms. If you need to find more than one element, then use ",(0,t.jsx)(n.code,{children:"findAllBy*"}),"."]}),"\n",(0,t.jsxs)(n.h3,{id:"find-all-by",children:[(0,t.jsx)(n.code,{children:"findAllBy*"})," queries"]}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"findAllBy*"})," queries return a promise which resolves to an array of matching elements. The promise is rejected if no elements match after a default timeout of 1000 ms."]}),"\n",(0,t.jsx)(n.admonition,{type:"info",children:(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"findBy*"})," and ",(0,t.jsx)(n.code,{children:"findAllBy*"})," queries accept optional ",(0,t.jsx)(n.code,{children:"waitForOptions"})," object argument which can contain ",(0,t.jsx)(n.code,{children:"timeout"}),", ",(0,t.jsx)(n.code,{children:"interval"})," and ",(0,t.jsx)(n.code,{children:"onTimeout"})," properies which have the same meaning as respective options for ",(0,t.jsx)(n.a,{href:"api#waitfor",children:(0,t.jsx)(n.code,{children:"waitFor"})})," function."]})}),"\n",(0,t.jsx)(n.admonition,{type:"info",children:(0,t.jsxs)(n.p,{children:["In cases when your ",(0,t.jsx)(n.code,{children:"findBy*"})," and ",(0,t.jsx)(n.code,{children:"findAllBy*"})," queries throw when not able to find matching elements it is useful to pass ",(0,t.jsx)(n.code,{children:"onTimeout: () => { screen.debug(); }"})," callback using ",(0,t.jsx)(n.code,{children:"waitForOptions"})," parameter."]})}),"\n",(0,t.jsx)(n.admonition,{type:"info",children:(0,t.jsxs)(n.p,{children:["In order to properly use ",(0,t.jsx)(n.code,{children:"findBy*"})," and ",(0,t.jsx)(n.code,{children:"findAllBy*"})," queries you need at least React >=16.9.0 (featuring async ",(0,t.jsx)(n.code,{children:"act"}),") or React Native >=0.61 (which comes with React >=16.9.0)."]})}),"\n",(0,t.jsx)(n.h2,{id:"query-predicates",children:"Query Predicates"}),"\n",(0,t.jsx)(n.p,{children:(0,t.jsxs)(n.em,{children:["Note: most methods like this one return a ",(0,t.jsx)(n.a,{href:"https://reactjs.org/docs/test-renderer.html#testinstance",children:(0,t.jsx)(n.code,{children:"ReactTestInstance"})})," with following properties that you may be interested in:"]})}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-typescript",children:"type ReactTestInstance = {\n type: string | Function;\n props: { [propName: string]: any };\n parent: ReactTestInstance | null;\n children: Array;\n};\n"})}),"\n",(0,t.jsx)(n.h3,{id:"by-role",children:(0,t.jsx)(n.code,{children:"ByRole"})}),"\n",(0,t.jsxs)(n.blockquote,{children:["\n",(0,t.jsx)(n.p,{children:"getByRole, getAllByRole, queryByRole, queryAllByRole, findByRole, findAllByRole"}),"\n"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-ts",children:"getByRole(\n role: TextMatch,\n options?: {\n name?: TextMatch\n disabled?: boolean,\n selected?: boolean,\n checked?: boolean | 'mixed',\n busy?: boolean,\n expanded?: boolean,\n value: {\n min?: number;\n max?: number;\n now?: number;\n text?: TextMatch;\n },\n includeHiddenElements?: boolean;\n }\n): ReactTestInstance;\n"})}),"\n",(0,t.jsxs)(n.p,{children:["Returns a ",(0,t.jsx)(n.code,{children:"ReactTestInstance"})," with matching ",(0,t.jsx)(n.code,{children:"role"})," or ",(0,t.jsx)(n.code,{children:"accessibilityRole"})," prop."]}),"\n",(0,t.jsxs)(n.admonition,{type:"info",children:[(0,t.jsxs)(n.p,{children:["In order for ",(0,t.jsx)(n.code,{children:"*ByRole"})," queries to match an element it needs to be considered an accessibility element:"]}),(0,t.jsxs)(n.ol,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"Text"}),", ",(0,t.jsx)(n.code,{children:"TextInput"})," and ",(0,t.jsx)(n.code,{children:"Switch"})," host elements are these by default."]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"View"})," host elements need an explicit ",(0,t.jsx)(n.a,{href:"https://reactnative.dev/docs/accessibility#accessible",children:(0,t.jsx)(n.code,{children:"accessible"})})," prop set to ",(0,t.jsx)(n.code,{children:"true"})]}),"\n",(0,t.jsxs)(n.li,{children:["Some React Native composite components like ",(0,t.jsx)(n.code,{children:"Pressable"})," & ",(0,t.jsx)(n.code,{children:"TouchableOpacity"})," render host ",(0,t.jsx)(n.code,{children:"View"})," element with ",(0,t.jsx)(n.code,{children:"accessible"})," prop already set."]}),"\n"]})]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-jsx",children:"import { render, screen } from '@testing-library/react-native';\n\nrender(\n \n Hello\n \n);\nconst element = screen.getByRole('button');\nconst element2 = screen.getByRole('button', { name: 'Hello' });\nconst element3 = screen.getByRole('button', { name: 'Hello', disabled: true });\n"})}),"\n",(0,t.jsx)(n.h4,{id:"by-role-options",children:"Options"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"name"}),": Finds an element with given ",(0,t.jsx)(n.code,{children:"role"}),"/",(0,t.jsx)(n.code,{children:"accessibilityRole"})," and an accessible name (= accessability label or text content)."]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"disabled"}),": You can filter elements by their disabled state (coming either from ",(0,t.jsx)(n.code,{children:"aria-disabled"})," prop or ",(0,t.jsx)(n.code,{children:"accessbilityState.disabled"})," prop). The possible values are ",(0,t.jsx)(n.code,{children:"true"})," or ",(0,t.jsx)(n.code,{children:"false"}),". Querying ",(0,t.jsx)(n.code,{children:"disabled: false"})," will also match elements with ",(0,t.jsx)(n.code,{children:"disabled: undefined"})," (see the ",(0,t.jsx)(n.a,{href:"https://github.com/callstack/react-native-testing-library/wiki/Accessibility:-State",children:"wiki"})," for more details)."]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["See ",(0,t.jsx)(n.a,{href:"https://reactnative.dev/docs/accessibility#accessibilitystate",children:"React Native's accessibilityState"})," docs to learn more about the ",(0,t.jsx)(n.code,{children:"disabled"})," state."]}),"\n",(0,t.jsxs)(n.li,{children:["This option can alternatively be expressed using the ",(0,t.jsxs)(n.a,{href:"jest-matchers#tobeenabled",children:[(0,t.jsx)(n.code,{children:"toBeEnabled()"})," / ",(0,t.jsx)(n.code,{children:"toBeDisabled()"})]})," Jest matchers."]}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"selected"}),": You can filter elements by their selected state (coming either from ",(0,t.jsx)(n.code,{children:"aria-selected"})," prop or ",(0,t.jsx)(n.code,{children:"accessbilityState.selected"})," prop). The possible values are ",(0,t.jsx)(n.code,{children:"true"})," or ",(0,t.jsx)(n.code,{children:"false"}),". Querying ",(0,t.jsx)(n.code,{children:"selected: false"})," will also match elements with ",(0,t.jsx)(n.code,{children:"selected: undefined"})," (see the ",(0,t.jsx)(n.a,{href:"https://github.com/callstack/react-native-testing-library/wiki/Accessibility:-State",children:"wiki"})," for more details)."]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["See ",(0,t.jsx)(n.a,{href:"https://reactnative.dev/docs/accessibility#accessibilitystate",children:"React Native's accessibilityState"})," docs to learn more about the ",(0,t.jsx)(n.code,{children:"selected"})," state."]}),"\n",(0,t.jsxs)(n.li,{children:["This option can alternatively be expressed using the ",(0,t.jsx)(n.a,{href:"jest-matchers#tobeselected",children:(0,t.jsx)(n.code,{children:"toBeSelected()"})})," Jest matcher."]}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"checked"}),": You can filter elements by their checked state (coming either from ",(0,t.jsx)(n.code,{children:"aria-checked"})," prop or ",(0,t.jsx)(n.code,{children:"accessbilityState.checked"})," prop). The possible values are ",(0,t.jsx)(n.code,{children:"true"}),", ",(0,t.jsx)(n.code,{children:"false"}),", or ",(0,t.jsx)(n.code,{children:'"mixed"'}),"."]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["See ",(0,t.jsx)(n.a,{href:"https://reactnative.dev/docs/accessibility#accessibilitystate",children:"React Native's accessibilityState"})," docs to learn more about the ",(0,t.jsx)(n.code,{children:"checked"})," state."]}),"\n",(0,t.jsxs)(n.li,{children:["This option can alternatively be expressed using the ",(0,t.jsxs)(n.a,{href:"jest-matchers#tobechecked",children:[(0,t.jsx)(n.code,{children:"toBeChecked()"})," / ",(0,t.jsx)(n.code,{children:"toBePartiallyChecked()"})]})," Jest matchers."]}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"busy"}),": You can filter elements by their busy state (coming either from ",(0,t.jsx)(n.code,{children:"aria-busy"})," prop or ",(0,t.jsx)(n.code,{children:"accessbilityState.busy"})," prop). The possible values are ",(0,t.jsx)(n.code,{children:"true"})," or ",(0,t.jsx)(n.code,{children:"false"}),". Querying ",(0,t.jsx)(n.code,{children:"busy: false"})," will also match elements with ",(0,t.jsx)(n.code,{children:"busy: undefined"})," (see the ",(0,t.jsx)(n.a,{href:"https://github.com/callstack/react-native-testing-library/wiki/Accessibility:-State",children:"wiki"})," for more details)."]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["See ",(0,t.jsx)(n.a,{href:"https://reactnative.dev/docs/accessibility#accessibilitystate",children:"React Native's accessibilityState"})," docs to learn more about the ",(0,t.jsx)(n.code,{children:"busy"})," state."]}),"\n",(0,t.jsxs)(n.li,{children:["This option can alternatively be expressed using the ",(0,t.jsx)(n.a,{href:"jest-matchers#tobebusy",children:(0,t.jsx)(n.code,{children:"toBeBusy()"})})," Jest matcher."]}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"expanded"}),": You can filter elements by their expanded state (coming either from ",(0,t.jsx)(n.code,{children:"aria-expanded"})," prop or ",(0,t.jsx)(n.code,{children:"accessbilityState.expanded"})," prop). The possible values are ",(0,t.jsx)(n.code,{children:"true"})," or ",(0,t.jsx)(n.code,{children:"false"}),"."]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["See ",(0,t.jsx)(n.a,{href:"https://reactnative.dev/docs/accessibility#accessibilitystate",children:"React Native's accessibilityState"})," docs to learn more about the ",(0,t.jsx)(n.code,{children:"expanded"})," state."]}),"\n",(0,t.jsxs)(n.li,{children:["This option can alternatively be expressed using the ",(0,t.jsxs)(n.a,{href:"jest-matchers#tobeexpanded",children:[(0,t.jsx)(n.code,{children:"toBeExpanded()"})," / ",(0,t.jsx)(n.code,{children:"toBeCollapsed()"})]})," Jest matchers."]}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"value"}),": Filter elements by their accessibility value, based on either ",(0,t.jsx)(n.code,{children:"aria-valuemin"}),", ",(0,t.jsx)(n.code,{children:"aria-valuemax"}),", ",(0,t.jsx)(n.code,{children:"aria-valuenow"}),", ",(0,t.jsx)(n.code,{children:"aria-valuetext"})," or ",(0,t.jsx)(n.code,{children:"accessibilityValue"})," props. Accessiblity value conceptually consists of numeric ",(0,t.jsx)(n.code,{children:"min"}),", ",(0,t.jsx)(n.code,{children:"max"})," and ",(0,t.jsx)(n.code,{children:"now"})," entries, as well as string ",(0,t.jsx)(n.code,{children:"text"})," entry."]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["See React Native ",(0,t.jsx)(n.a,{href:"https://reactnative.dev/docs/accessibility#accessibilityvalue",children:"accessibilityValue"})," docs to learn more about the accessibility value concept."]}),"\n",(0,t.jsxs)(n.li,{children:["This option can alternatively be expressed using the ",(0,t.jsx)(n.a,{href:"jest-matchers#tohaveaccessibilityvalue",children:(0,t.jsx)(n.code,{children:"toHaveAccessibilityValue()"})})," Jest matcher."]}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,t.jsx)(n.h3,{id:"by-text",children:(0,t.jsx)(n.code,{children:"ByText"})}),"\n",(0,t.jsxs)(n.blockquote,{children:["\n",(0,t.jsx)(n.p,{children:"getByText, getAllByText, queryByText, queryAllByText, findByText, findAllByText"}),"\n"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-ts",children:"getByText(\n text: TextMatch,\n options?: {\n exact?: boolean;\n normalizer?: (text: string) => string;\n includeHiddenElements?: boolean;\n }\n): ReactTestInstance;\n"})}),"\n",(0,t.jsxs)(n.p,{children:["Returns a ",(0,t.jsx)(n.code,{children:"ReactTestInstance"})," with matching text \u2013 may be a string or regular expression."]}),"\n",(0,t.jsxs)(n.p,{children:["This method will join ",(0,t.jsx)(n.code,{children:""})," siblings to find matches, similarly to ",(0,t.jsx)(n.a,{href:"https://reactnative.dev/docs/text#containers",children:"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."]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-jsx",children:"import { render, screen } from '@testing-library/react-native';\n\nrender();\nconst element = screen.getByText('banana');\n"})}),"\n",(0,t.jsx)(n.h3,{id:"by-placeholder-text",children:(0,t.jsx)(n.code,{children:"ByPlaceholderText"})}),"\n",(0,t.jsxs)(n.blockquote,{children:["\n",(0,t.jsx)(n.p,{children:"getByPlaceholderText, getAllByPlaceholderText, queryByPlaceholderText, queryAllByPlaceholderText, findByPlaceholderText, findAllByPlaceholderText"}),"\n"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-ts",children:"getByPlaceholderText(\n text: TextMatch,\n options?: {\n exact?: boolean;\n normalizer?: (text: string) => string;\n includeHiddenElements?: boolean;\n }\n): ReactTestInstance;\n"})}),"\n",(0,t.jsxs)(n.p,{children:["Returns a ",(0,t.jsx)(n.code,{children:"ReactTestInstance"})," for a ",(0,t.jsx)(n.code,{children:"TextInput"})," with a matching placeholder \u2013 may be a string or regular expression."]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-jsx",children:"import { render, screen } from '@testing-library/react-native';\n\nrender();\nconst element = screen.getByPlaceholderText('username');\n"})}),"\n",(0,t.jsx)(n.h3,{id:"by-display-value",children:(0,t.jsx)(n.code,{children:"ByDisplayValue"})}),"\n",(0,t.jsxs)(n.blockquote,{children:["\n",(0,t.jsx)(n.p,{children:"getByDisplayValue, getAllByDisplayValue, queryByDisplayValue, queryAllByDisplayValue, findByDisplayValue, findAllByDisplayValue"}),"\n"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-ts",children:"getByDisplayValue(\n value: TextMatch,\n options?: {\n exact?: boolean;\n normalizer?: (text: string) => string;\n includeHiddenElements?: boolean;\n },\n): ReactTestInstance;\n"})}),"\n",(0,t.jsxs)(n.p,{children:["Returns a ",(0,t.jsx)(n.code,{children:"ReactTestInstance"})," for a ",(0,t.jsx)(n.code,{children:"TextInput"})," with a matching display value \u2013 may be a string or regular expression."]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-jsx",children:"import { render, screen } from '@testing-library/react-native';\n\nrender();\nconst element = screen.getByDisplayValue('username');\n"})}),"\n",(0,t.jsx)(n.h3,{id:"by-test-id",children:(0,t.jsx)(n.code,{children:"ByTestId"})}),"\n",(0,t.jsxs)(n.blockquote,{children:["\n",(0,t.jsx)(n.p,{children:"getByTestId, getAllByTestId, queryByTestId, queryAllByTestId, findByTestId, findAllByTestId"}),"\n"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-ts",children:"getByTestId(\n testId: TextMatch,\n options?: {\n exact?: boolean;\n normalizer?: (text: string) => string;\n includeHiddenElements?: boolean;\n },\n): ReactTestInstance;\n"})}),"\n",(0,t.jsxs)(n.p,{children:["Returns a ",(0,t.jsx)(n.code,{children:"ReactTestInstance"})," with matching ",(0,t.jsx)(n.code,{children:"testID"})," prop. ",(0,t.jsx)(n.code,{children:"testID"})," \u2013 may be a string or a regular expression."]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-jsx",children:"import { render, screen } from '@testing-library/react-native';\n\nrender();\nconst element = screen.getByTestId('unique-id');\n"})}),"\n",(0,t.jsx)(n.admonition,{type:"info",children:(0,t.jsxs)(n.p,{children:["In the spirit of ",(0,t.jsx)(n.a,{href:"https://testing-library.com/docs/guiding-principles",children:"the guiding principles"}),", it is recommended to use this only after the other queries don't work for your use case. Using ",(0,t.jsx)(n.code,{children:"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 ",(0,t.jsx)(n.a,{href:"https://kentcdodds.com/blog/making-your-ui-tests-resilient-to-change",children:'"Making your UI tests resilient to change"'}),"."]})}),"\n",(0,t.jsx)(n.h3,{id:"by-label-text",children:(0,t.jsx)(n.code,{children:"ByLabelText"})}),"\n",(0,t.jsxs)(n.blockquote,{children:["\n",(0,t.jsx)(n.p,{children:"getByLabelText, getAllByLabelText, queryByLabelText, queryAllByLabelText, findByLabelText, findAllByLabelText"}),"\n"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-ts",children:"getByLabelText(\n text: TextMatch,\n options?: {\n exact?: boolean;\n normalizer?: (text: string) => string;\n includeHiddenElements?: boolean;\n },\n): ReactTestInstance;\n"})}),"\n",(0,t.jsxs)(n.p,{children:["Returns a ",(0,t.jsx)(n.code,{children:"ReactTestInstance"})," with matching label:"]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["either by matching ",(0,t.jsx)(n.a,{href:"https://reactnative.dev/docs/accessibility#aria-label",children:(0,t.jsx)(n.code,{children:"aria-label"})}),"/",(0,t.jsx)(n.a,{href:"https://reactnative.dev/docs/accessibility#accessibilitylabel",children:(0,t.jsx)(n.code,{children:"accessibilityLabel"})})," prop"]}),"\n",(0,t.jsxs)(n.li,{children:["or by matching text content of view referenced by ",(0,t.jsx)(n.a,{href:"https://reactnative.dev/docs/accessibility#aria-labelledby-android",children:(0,t.jsx)(n.code,{children:"aria-labelledby"})}),"/",(0,t.jsx)(n.a,{href:"https://reactnative.dev/docs/accessibility#accessibilitylabelledby-android",children:(0,t.jsx)(n.code,{children:"accessibilityLabelledBy"})})," prop"]}),"\n"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-jsx",children:"import { render, screen } from '@testing-library/react-native';\n\nrender();\nconst element = screen.getByLabelText('my-label');\n"})}),"\n",(0,t.jsxs)(n.h3,{id:"by-hint-text",children:[(0,t.jsx)(n.code,{children:"ByHintText"}),", ",(0,t.jsx)(n.code,{children:"ByA11yHint"}),", ",(0,t.jsx)(n.code,{children:"ByAccessibilityHint"})]}),"\n",(0,t.jsxs)(n.blockquote,{children:["\n",(0,t.jsx)(n.p,{children:"getByA11yHint, getAllByA11yHint, queryByA11yHint, queryAllByA11yHint, findByA11yHint, findAllByA11yHint\ngetByAccessibilityHint, getAllByAccessibilityHint, queryByAccessibilityHint, queryAllByAccessibilityHint, findByAccessibilityHint, findAllByAccessibilityHint\ngetByHintText, getAllByHintText, queryByHintText, queryAllByHintText, findByHintText, findAllByHintText"}),"\n"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-ts",children:"getByHintText(\n hint: TextMatch,\n options?: {\n exact?: boolean;\n normalizer?: (text: string) => string;\n includeHiddenElements?: boolean;\n },\n): ReactTestInstance;\n"})}),"\n",(0,t.jsxs)(n.p,{children:["Returns a ",(0,t.jsx)(n.code,{children:"ReactTestInstance"})," with matching ",(0,t.jsx)(n.code,{children:"accessibilityHint"})," prop."]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-jsx",children:"import { render, screen } from '@testing-library/react-native';\n\nrender();\nconst element = screen.getByHintText('Plays a song');\n"})}),"\n",(0,t.jsx)(n.admonition,{type:"info",children:(0,t.jsxs)(n.p,{children:["Please consult ",(0,t.jsxs)(n.a,{href:"https://developer.apple.com/documentation/objectivec/nsobject/1615093-accessibilityhint",children:["Apple guidelines on how ",(0,t.jsx)(n.code,{children:"accessibilityHint"})," should be used"]}),"."]})}),"\n",(0,t.jsxs)(n.h3,{id:"by-accessibility-state",children:[(0,t.jsx)(n.code,{children:"ByA11yState"}),", ",(0,t.jsx)(n.code,{children:"ByAccessibilityState"})," (deprecated)"]}),"\n",(0,t.jsxs)(n.admonition,{type:"caution",children:[(0,t.jsx)(n.p,{children:"This query has been marked deprecated, as is typically too general to give meaningful results. Therefore, it's better to use one of following options:"}),(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.a,{href:"#by-role",children:(0,t.jsx)(n.code,{children:"*ByRole"})})," query with relevant state options: ",(0,t.jsx)(n.code,{children:"disabled"}),", ",(0,t.jsx)(n.code,{children:"selected"}),", ",(0,t.jsx)(n.code,{children:"checked"}),", ",(0,t.jsx)(n.code,{children:"expanded"})," and ",(0,t.jsx)(n.code,{children:"busy"})]}),"\n",(0,t.jsxs)(n.li,{children:["use built-in Jest matchers to check the state of element found using some other query:","\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["enabled state: ",(0,t.jsxs)(n.a,{href:"jest-matchers#tobeenabled",children:[(0,t.jsx)(n.code,{children:"toBeEnabled()"})," / ",(0,t.jsx)(n.code,{children:"toBeDisabled()"})]})]}),"\n",(0,t.jsxs)(n.li,{children:["checked state: ",(0,t.jsxs)(n.a,{href:"jest-matchers#tobechecked",children:[(0,t.jsx)(n.code,{children:"toBeChecked()"})," / ",(0,t.jsx)(n.code,{children:"toBePartiallyChecked()"})]})]}),"\n",(0,t.jsxs)(n.li,{children:["selected state: ",(0,t.jsx)(n.a,{href:"jest-matchers#tobeselected",children:(0,t.jsx)(n.code,{children:"toBeSelected()"})})]}),"\n",(0,t.jsxs)(n.li,{children:["expanded state: ",(0,t.jsxs)(n.a,{href:"jest-matchers#tobeexpanded",children:[(0,t.jsx)(n.code,{children:"toBeExpanded()"})," / ",(0,t.jsx)(n.code,{children:"toBeCollapsed()"})]})]}),"\n",(0,t.jsxs)(n.li,{children:["busy state: ",(0,t.jsx)(n.a,{href:"jest-matchers#tobebusy",children:(0,t.jsx)(n.code,{children:"toBeBusy()"})})]}),"\n"]}),"\n"]}),"\n"]})]}),"\n",(0,t.jsxs)(n.blockquote,{children:["\n",(0,t.jsx)(n.p,{children:"getByA11yState, getAllByA11yState, queryByA11yState, queryAllByA11yState, findByA11yState, findAllByA11yState\ngetByAccessibilityState, getAllByAccessibilityState, queryByAccessibilityState, queryAllByAccessibilityState, findByAccessibilityState, findAllByAccessibilityState"}),"\n"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-ts",children:"getByA11yState(\n state: {\n disabled?: boolean,\n selected?: boolean,\n checked?: boolean | 'mixed',\n busy?: boolean,\n expanded?: boolean,\n },\n options?: {\n includeHiddenElements?: boolean;\n },\n): ReactTestInstance;\n"})}),"\n",(0,t.jsxs)(n.p,{children:["Returns a ",(0,t.jsx)(n.code,{children:"ReactTestInstance"})," with matching ",(0,t.jsx)(n.code,{children:"accessibilityState"})," prop or ARIA state props: ",(0,t.jsx)(n.code,{children:"aria-disabled"}),", ",(0,t.jsx)(n.code,{children:"aria-selected"}),", ",(0,t.jsx)(n.code,{children:"aria-checked"}),", ",(0,t.jsx)(n.code,{children:"aria-busy"}),", and ",(0,t.jsx)(n.code,{children:"aria-expanded"}),"."]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-jsx",children:"import { render, screen } from '@testing-library/react-native';\n\nrender();\nconst element = screen.getByA11yState({ disabled: true });\n"})}),"\n",(0,t.jsxs)(n.admonition,{type:"note",children:[(0,t.jsxs)(n.h4,{id:"default-state-for-disabled-selected-and-busy-keys",children:["Default state for: ",(0,t.jsx)(n.code,{children:"disabled"}),", ",(0,t.jsx)(n.code,{children:"selected"}),", and ",(0,t.jsx)(n.code,{children:"busy"})," keys"]}),(0,t.jsxs)(n.p,{children:["Passing ",(0,t.jsx)(n.code,{children:"false"})," matcher value will match both elements with explicit ",(0,t.jsx)(n.code,{children:"false"})," state value and without explicit state value."]}),(0,t.jsxs)(n.p,{children:["For instance, ",(0,t.jsx)(n.code,{children:"getByA11yState({ disabled: false })"})," will match elements with following props:"]}),(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.code,{children:"accessibilityState={{ disabled: false, ... }}"})}),"\n",(0,t.jsxs)(n.li,{children:["no ",(0,t.jsx)(n.code,{children:"disabled"})," key under ",(0,t.jsx)(n.code,{children:"accessibilityState"})," prop, e.g. ",(0,t.jsx)(n.code,{children:"accessibilityState={{}}"})]}),"\n",(0,t.jsxs)(n.li,{children:["no ",(0,t.jsx)(n.code,{children:"accessibilityState"})," prop at all"]}),"\n"]}),(0,t.jsxs)(n.h4,{id:"default-state-for-checked-and-expanded-keys",children:["Default state for: ",(0,t.jsx)(n.code,{children:"checked"})," and ",(0,t.jsx)(n.code,{children:"expanded"})," keys"]}),(0,t.jsxs)(n.p,{children:["Passing ",(0,t.jsx)(n.code,{children:"false"})," matcher value will only match elements with explicit ",(0,t.jsx)(n.code,{children:"false"})," state value."]}),(0,t.jsxs)(n.p,{children:["For instance, ",(0,t.jsx)(n.code,{children:"getByA11yState({ checked: false })"})," will only match elements with:"]}),(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.code,{children:"accessibilityState={{ checked: false, ... }}"})}),"\n"]}),(0,t.jsx)(n.p,{children:"but will not match elements with following props:"}),(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["no ",(0,t.jsx)(n.code,{children:"checked"})," key under ",(0,t.jsx)(n.code,{children:"accessibilityState"})," prop, e.g. ",(0,t.jsx)(n.code,{children:"accessibilityState={{}}"})]}),"\n",(0,t.jsxs)(n.li,{children:["no ",(0,t.jsx)(n.code,{children:"accessibilityState"})," prop at all"]}),"\n"]}),(0,t.jsx)(n.p,{children:"The difference in handling default values is made to reflect observed accessibility behaviour on iOS and Android platforms."})]}),"\n",(0,t.jsxs)(n.h3,{id:"by-accessibility-value",children:[(0,t.jsx)(n.code,{children:"ByA11yValue"}),", ",(0,t.jsx)(n.code,{children:"ByAccessibilityValue"})," (deprecated)"]}),"\n",(0,t.jsxs)(n.admonition,{type:"caution",children:[(0,t.jsx)(n.p,{children:"This query has been marked deprecated, as is typically too general to give meaningful results. Therefore, it's better to use one of following options:"}),(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.a,{href:"jest-matchers#tohaveaccessibilityvalue",children:(0,t.jsx)(n.code,{children:"toHaveAccessibilityValue()"})})," Jest matcher to check the state of element found using some other query"]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.a,{href:"#by-role",children:(0,t.jsx)(n.code,{children:"*ByRole"})})," query with ",(0,t.jsx)(n.code,{children:"value"})," option"]}),"\n"]})]}),"\n",(0,t.jsxs)(n.blockquote,{children:["\n",(0,t.jsx)(n.p,{children:"getByA11yValue, getAllByA11yValue, queryByA11yValue, queryAllByA11yValue, findByA11yValue, findAllByA11yValue\ngetByAccessibilityValue, getAllByAccessibilityValue, queryByAccessibilityValue, queryAllByAccessibilityValue, findByAccessibilityValue, findAllByAccessibilityValue"}),"\n"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-ts",children:"getByA11yValue(\n value: {\n min?: number;\n max?: number;\n now?: number;\n text?: TextMatch;\n },\n options?: {\n includeHiddenElements?: boolean;\n },\n): ReactTestInstance;\n"})}),"\n",(0,t.jsxs)(n.p,{children:["Returns a host element with matching accessibility value based on ",(0,t.jsx)(n.code,{children:"aria-valuemin"}),", ",(0,t.jsx)(n.code,{children:"aria-valuemax"}),", ",(0,t.jsx)(n.code,{children:"aria-valuenow"}),", ",(0,t.jsx)(n.code,{children:"aria-valuetext"})," & ",(0,t.jsx)(n.code,{children:"accessibilityValue"})," props. Only value entires provided to the query will be used to match elements. Element might have additional accessibility value entries and still be matched."]}),"\n",(0,t.jsxs)(n.p,{children:["When querying by ",(0,t.jsx)(n.code,{children:"text"})," entry a string or regex might be used."]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-jsx",children:"import { render, screen } from '@testing-library/react-native';\n\nrender();\nconst element = screen.getByA11yValue({ now: 25 });\nconst element2 = screen.getByA11yValue({ text: /25/ });\n"})}),"\n",(0,t.jsx)(n.h3,{id:"common-options",children:"Common options"}),"\n",(0,t.jsxs)(n.p,{children:["Usually query first argument can be a ",(0,t.jsx)(n.strong,{children:"string"})," or a ",(0,t.jsx)(n.strong,{children:"regex"}),". All queries take at least the ",(0,t.jsx)(n.a,{href:"#hidden-option",children:(0,t.jsx)(n.code,{children:"hidden"})})," option as an optionnal second argument and some queries accept more options which change string matching behaviour. See ",(0,t.jsx)(n.a,{href:"#textmatch",children:"TextMatch"})," for more info."]}),"\n",(0,t.jsxs)(n.h4,{id:"includehiddenelements-option",children:[(0,t.jsx)(n.code,{children:"includeHiddenElements"})," option"]}),"\n",(0,t.jsxs)(n.p,{children:["All queries have the ",(0,t.jsx)(n.code,{children:"includeHiddenElements"})," option which affects whether ",(0,t.jsx)(n.a,{href:"/react-native-testing-library/docs/api#ishiddenfromaccessibility",children:"elements hidden from accessibility"})," are matched by the query. By default queries will not match hidden elements, because the users of the app would not be able to see such elements."]}),"\n",(0,t.jsxs)(n.p,{children:["You can configure the default value with the ",(0,t.jsxs)(n.a,{href:"/react-native-testing-library/docs/api#configure",children:[(0,t.jsx)(n.code,{children:"configure"})," function"]}),"."]}),"\n",(0,t.jsxs)(n.p,{children:["This option is also available as ",(0,t.jsx)(n.code,{children:"hidden"})," alias for compatibility with ",(0,t.jsx)(n.a,{href:"https://testing-library.com/docs/queries/byrole#hidden",children:"React Testing Library"}),"."]}),"\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.strong,{children:"Examples"})}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-tsx",children:"render(Hidden from accessibility);\n\n// Exclude hidden elements\nexpect(\n screen.queryByText('Hidden from accessibility', {\n includeHiddenElements: false,\n })\n).not.toBeOnTheScreen();\n\n// Include hidden elements\nexpect(screen.getByText('Hidden from accessibility')).toBeOnTheScreen();\nexpect(\n screen.getByText('Hidden from accessibility', { includeHiddenElements: true })\n).toBeOnTheScreen();\n"})}),"\n",(0,t.jsx)(n.h2,{id:"textmatch-type",children:"TextMatch type"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-ts",children:"type TextMatch = string | RegExp;\n"})}),"\n",(0,t.jsxs)(n.p,{children:["Most of the query APIs take a ",(0,t.jsx)(n.code,{children:"TextMatch"})," as an argument, which means the argument can be either a ",(0,t.jsx)(n.em,{children:"string"})," or ",(0,t.jsx)(n.em,{children:"regex"}),"."]}),"\n",(0,t.jsx)(n.h3,{id:"examples",children:"Examples"}),"\n",(0,t.jsx)(n.p,{children:"Given the following render:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-jsx",children:"render(Hello World);\n"})}),"\n",(0,t.jsxs)(n.p,{children:["Will ",(0,t.jsx)(n.strong,{children:"find a match"}),":"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-js",children:"// Matching a string:\nscreen.getByText('Hello World'); // full string match\nscreen.getByText('llo Worl', { exact: false }); // substring match\nscreen.getByText('hello world', { exact: false }); // ignore case-sensitivity\n\n// Matching a regex:\nscreen.getByText(/World/); // substring match\nscreen.getByText(/world/i); // substring match, ignore case\nscreen.getByText(/^hello world$/i); // full string match, ignore case-sensitivity\nscreen.getByText(/Hello W?oRlD/i); // advanced regex\n"})}),"\n",(0,t.jsxs)(n.p,{children:["Will ",(0,t.jsx)(n.strong,{children:"NOT find a match"})]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-js",children:"// substring does not match\nscreen.getByText('llo Worl');\n// full string does not match\nscreen.getByText('Goodbye World');\n\n// case-sensitive regex with different case\nscreen.getByText(/hello world/);\n"})}),"\n",(0,t.jsx)(n.h3,{id:"text-match-options",children:"Options"}),"\n",(0,t.jsx)(n.h4,{id:"precision",children:"Precision"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-typescript",children:"type TextMatchOptions = {\n exact?: boolean;\n normalizer?: (text: string) => string;\n};\n"})}),"\n",(0,t.jsxs)(n.p,{children:["Queries that take a ",(0,t.jsx)(n.code,{children:"TextMatch"})," also accept an object as the second argument that can contain options that affect the precision of string matching:"]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"exact"}),": Defaults to ",(0,t.jsx)(n.code,{children:"true"}),"; matches full strings, case-sensitive. When false, matches substrings and is not case-sensitive.","\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"exact"})," has no effect on regex argument."]}),"\n",(0,t.jsxs)(n.li,{children:["In most cases using a ",(0,t.jsx)(n.code,{children:"regex"})," instead of a string gives you more control over fuzzy matching and should be preferred over ",(0,t.jsx)(n.code,{children:"{ exact: false }"}),"."]}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"normalizer"}),": An optional function which overrides normalization behavior. See ",(0,t.jsx)(n.a,{href:"#normalization",children:"Normalization"}),"."]}),"\n"]}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"exact"})," option defaults to ",(0,t.jsx)(n.code,{children:"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."]}),"\n",(0,t.jsx)(n.h4,{id:"normalization",children:"Normalization"}),"\n",(0,t.jsx)(n.p,{children:"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."}),"\n",(0,t.jsxs)(n.p,{children:["If you want to prevent that normalization, or provide alternative normalization (e.g. to remove Unicode control characters), you can provide a ",(0,t.jsx)(n.code,{children:"normalizer"})," function in the options object. This function will be given a string and is expected to return a normalized version of that string."]}),"\n",(0,t.jsx)(n.admonition,{type:"info",children:(0,t.jsxs)(n.p,{children:["Specifying a value for ",(0,t.jsx)(n.code,{children:"normalizer"})," replaces the built-in normalization, but you can call ",(0,t.jsx)(n.code,{children:"getDefaultNormalizer"})," to obtain a built-in normalizer, either to adjust that normalization or to call it from your own normalizer."]})}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"getDefaultNormalizer"})," take options object which allows the selection of behaviour:"]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"trim"}),": Defaults to ",(0,t.jsx)(n.code,{children:"true"}),". Trims leading and trailing whitespace."]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"collapseWhitespace"}),": Defaults to ",(0,t.jsx)(n.code,{children:"true"}),". Collapses inner whitespace (newlines, tabs repeated spaces) into a single space."]}),"\n"]}),"\n",(0,t.jsx)(n.h5,{id:"normalization-examples",children:"Normalization Examples"}),"\n",(0,t.jsx)(n.p,{children:"To perform a match against text without trimming:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-typescript",children:"screen.getByText(node, 'text', {\n normalizer: getDefaultNormalizer({ trim: false }),\n});\n"})}),"\n",(0,t.jsx)(n.p,{children:"To override normalization to remove some Unicode characters whilst keeping some (but not all) of the built-in normalization behavior:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-typescript",children:"screen.getByText(node, 'text', {\n normalizer: (str) => getDefaultNormalizer({ trim: false })(str).replace(/[\\u200E-\\u200F]*/g, ''),\n});\n"})}),"\n",(0,t.jsx)(n.h2,{id:"legacy-unit-testing-helpers",children:"Legacy unit testing helpers"}),"\n",(0,t.jsxs)(n.blockquote,{children:["\n",(0,t.jsx)(n.p,{children:"Use sparingly and responsibly, escape hatches here"}),"\n"]}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"render"})," from ",(0,t.jsx)(n.code,{children:"@testing-library/react-native"})," exposes additional queries that ",(0,t.jsx)(n.strong,{children:"should not be used in component integration testing"}),", but some users (like component library creators) interested in unit testing some components may find helpful."]}),"\n",(0,t.jsxs)(i,{children:[(0,t.jsx)("summary",{children:"Queries helpful in unit testing"}),(0,t.jsx)(n.p,{children:"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."}),(0,t.jsx)(n.h3,{id:"unsafe_bytype",children:(0,t.jsx)(n.code,{children:"UNSAFE_ByType"})}),(0,t.jsxs)(n.blockquote,{children:["\n",(0,t.jsx)(n.p,{children:"UNSAFE_getByType, UNSAFE_getAllByType, UNSAFE_queryByType, UNSAFE_queryAllByType"}),"\n"]}),(0,t.jsxs)(n.p,{children:["Returns a ",(0,t.jsx)(n.code,{children:"ReactTestInstance"})," with matching a React component type."]}),(0,t.jsx)(n.admonition,{type:"caution",children:(0,t.jsx)(n.p,{children:"This query has been marked unsafe, since it requires knowledge about implementation details of the component. Use responsibly."})}),(0,t.jsx)(n.h3,{id:"unsafe_byprops",children:(0,t.jsx)(n.code,{children:"UNSAFE_ByProps"})}),(0,t.jsxs)(n.blockquote,{children:["\n",(0,t.jsx)(n.p,{children:"UNSAFE_getByProps, UNSAFE_getAllByProps, UNSAFE_queryByProps, UNSAFE_queryAllByProps"}),"\n"]}),(0,t.jsxs)(n.p,{children:["Returns a ",(0,t.jsx)(n.code,{children:"ReactTestInstance"})," with matching props object."]}),(0,t.jsx)(n.admonition,{type:"caution",children:(0,t.jsx)(n.p,{children:"This query has been marked unsafe, since it requires knowledge about implementation details of the component. Use responsibly."})})]})]})}function x(e={}){const{wrapper:n}={...(0,s.a)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(h,{...e})}):h(e)}},1151:(e,n,i)=>{i.d(n,{Z:()=>r,a:()=>c});var t=i(7294);const s={},l=t.createContext(s);function c(e){const n=t.useContext(l);return t.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:c(e.components),t.createElement(l.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/7ad239b9.d78ac751.js b/assets/js/7ad239b9.d78ac751.js new file mode 100644 index 00000000..92ae77b4 --- /dev/null +++ b/assets/js/7ad239b9.d78ac751.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkreact_native_testing_library_website=self.webpackChunkreact_native_testing_library_website||[]).push([[430],{2063:(e,n,i)=>{i.d(n,{Z:()=>c});i(7294);var t=i(1351);const s={tableOfContentsInline:"tableOfContentsInline_prmo"};var l=i(5893);function c(e){let{toc:n,minHeadingLevel:i,maxHeadingLevel:c}=e;return(0,l.jsx)("div",{className:s.tableOfContentsInline,children:(0,l.jsx)(t.Z,{toc:n,minHeadingLevel:i,maxHeadingLevel:c,className:"table-of-contents",linkClassName:null})})}},1351:(e,n,i)=>{i.d(n,{Z:()=>j});var t=i(7294),s=i(6793);function l(e){const n=e.map((e=>({...e,parentIndex:-1,children:[]}))),i=Array(7).fill(-1);n.forEach(((e,n)=>{const t=i.slice(2,e.level);e.parentIndex=Math.max(...t),i[e.level]=n}));const t=[];return n.forEach((e=>{const{parentIndex:i,...s}=e;i>=0?n[i].children.push(s):t.push(s)})),t}function c(e){let{toc:n,minHeadingLevel:i,maxHeadingLevel:t}=e;return n.flatMap((e=>{const n=c({toc:e.children,minHeadingLevel:i,maxHeadingLevel:t});return function(e){return e.level>=i&&e.level<=t}(e)?[{...e,children:n}]:n}))}function r(e){const n=e.getBoundingClientRect();return n.top===n.bottom?r(e.parentNode):n}function a(e,n){var i;let{anchorTopOffset:t}=n;const s=e.find((e=>r(e).top>=t));if(s){var l;return function(e){return e.top>0&&e.bottom{e.current=n?0:document.querySelector(".navbar").clientHeight}),[n]),e}function o(e){const n=(0,t.useRef)(void 0),i=d();(0,t.useEffect)((()=>{if(!e)return()=>{};const{linkClassName:t,linkActiveClassName:s,minHeadingLevel:l,maxHeadingLevel:c}=e;function r(){const e=function(e){return Array.from(document.getElementsByClassName(e))}(t),r=function(e){let{minHeadingLevel:n,maxHeadingLevel:i}=e;const t=[];for(let s=n;s<=i;s+=1)t.push("h"+s+".anchor");return Array.from(document.querySelectorAll(t.join()))}({minHeadingLevel:l,maxHeadingLevel:c}),d=a(r,{anchorTopOffset:i.current}),o=e.find((e=>d&&d.id===function(e){return decodeURIComponent(e.href.substring(e.href.indexOf("#")+1))}(e)));e.forEach((e=>{!function(e,i){i?(n.current&&n.current!==e&&n.current.classList.remove(s),e.classList.add(s),n.current=e):e.classList.remove(s)}(e,e===o)}))}return document.addEventListener("scroll",r),document.addEventListener("resize",r),r(),()=>{document.removeEventListener("scroll",r),document.removeEventListener("resize",r)}}),[e,i])}var h=i(8746),x=i(5893);function u(e){let{toc:n,className:i,linkClassName:t,isChild:s}=e;return n.length?(0,x.jsx)("ul",{className:s?void 0:i,children:n.map((e=>(0,x.jsxs)("li",{children:[(0,x.jsx)(h.Z,{to:"#"+e.id,className:null!=t?t:void 0,dangerouslySetInnerHTML:{__html:e.value}}),(0,x.jsx)(u,{isChild:!0,toc:e.children,className:i,linkClassName:t})]},e.id)))}):null}const y=t.memo(u);function j(e){let{toc:n,className:i="table-of-contents table-of-contents__left-border",linkClassName:r="table-of-contents__link",linkActiveClassName:a,minHeadingLevel:d,maxHeadingLevel:h,...u}=e;const j=(0,s.L)(),m=null!=d?d:j.tableOfContents.minHeadingLevel,p=null!=h?h:j.tableOfContents.maxHeadingLevel,b=function(e){let{toc:n,minHeadingLevel:i,maxHeadingLevel:s}=e;return(0,t.useMemo)((()=>c({toc:l(n),minHeadingLevel:i,maxHeadingLevel:s})),[n,i,s])}({toc:n,minHeadingLevel:m,maxHeadingLevel:p});return o((0,t.useMemo)((()=>{if(r&&a)return{linkClassName:r,linkActiveClassName:a,minHeadingLevel:m,maxHeadingLevel:p}}),[r,a,m,p])),(0,x.jsx)(y,{toc:b,className:i,linkClassName:r,...u})}},4920:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>d,contentTitle:()=>r,default:()=>x,frontMatter:()=>c,metadata:()=>a,toc:()=>o});var t=i(5893),s=i(1151),l=i(2063);const c={id:"api-queries",title:"Queries"},r=void 0,a={id:"api-queries",title:"Queries",description:"Query Variants",source:"@site/docs/Queries.md",sourceDirName:".",slug:"/api-queries",permalink:"/react-native-testing-library/docs/api-queries",draft:!1,unlisted:!1,editUrl:"https://github.com/callstack/react-native-testing-library/blob/main/website/docs/Queries.md",tags:[],version:"current",frontMatter:{id:"api-queries",title:"Queries"},sidebar:"docs",previous:{title:"API",permalink:"/react-native-testing-library/docs/api"},next:{title:"User Event",permalink:"/react-native-testing-library/docs/user-event"}},d={},o=[{value:"Query Variants",id:"query-variants",level:2},{value:"getBy* queries",id:"get-by",level:3},{value:"getAllBy* queries",id:"get-all-by",level:3},{value:"queryBy* queries",id:"query-by",level:3},{value:"queryAllBy* queries",id:"query-all-by",level:3},{value:"findBy* queries",id:"find-by",level:3},{value:"findAllBy* queries",id:"find-all-by",level:3},{value:"Query Predicates",id:"query-predicates",level:2},{value:"ByRole",id:"by-role",level:3},{value:"Options",id:"by-role-options",level:4},{value:"ByText",id:"by-text",level:3},{value:"ByPlaceholderText",id:"by-placeholder-text",level:3},{value:"ByDisplayValue",id:"by-display-value",level:3},{value:"ByTestId",id:"by-test-id",level:3},{value:"ByLabelText",id:"by-label-text",level:3},{value:"ByHintText, ByA11yHint, ByAccessibilityHint",id:"by-hint-text",level:3},{value:"ByA11yState, ByAccessibilityState (deprecated)",id:"by-accessibility-state",level:3},{value:"Default state for: disabled, selected, and busy keys",id:"default-state-for-disabled-selected-and-busy-keys",level:4},{value:"Default state for: checked and expanded keys",id:"default-state-for-checked-and-expanded-keys",level:4},{value:"ByA11yValue, ByAccessibilityValue (deprecated)",id:"by-accessibility-value",level:3},{value:"Common options",id:"common-options",level:3},{value:"includeHiddenElements option",id:"includehiddenelements-option",level:4},{value:"TextMatch type",id:"textmatch-type",level:2},{value:"Examples",id:"examples",level:3},{value:"Options",id:"text-match-options",level:3},{value:"Precision",id:"precision",level:4},{value:"Normalization",id:"normalization",level:4},{value:"Normalization Examples",id:"normalization-examples",level:5},{value:"Legacy unit testing helpers",id:"legacy-unit-testing-helpers",level:2},{value:"UNSAFE_ByType",id:"unsafe_bytype",level:3},{value:"UNSAFE_ByProps",id:"unsafe_byprops",level:3}];function h(e){const n={a:"a",admonition:"admonition",blockquote:"blockquote",code:"code",em:"em",h2:"h2",h3:"h3",h4:"h4",h5:"h5",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.a)(),...e.components},{Details:i}=n;return i||function(e,n){throw new Error("Expected "+(n?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}("Details",!0),(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(l.Z,{toc:o}),"\n",(0,t.jsx)(n.h2,{id:"query-variants",children:"Query Variants"}),"\n",(0,t.jsxs)(n.blockquote,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"getBy*"})," queries are shown by default in the ",(0,t.jsx)(n.a,{href:"#queries",children:"query documentation"}),"\nbelow."]}),"\n"]}),"\n",(0,t.jsxs)(n.h3,{id:"get-by",children:[(0,t.jsx)(n.code,{children:"getBy*"})," queries"]}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"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. If you need to find more than one element, then use ",(0,t.jsx)(n.code,{children:"getAllBy"}),"."]}),"\n",(0,t.jsxs)(n.h3,{id:"get-all-by",children:[(0,t.jsx)(n.code,{children:"getAllBy*"})," queries"]}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"getAllBy*"})," queries return an array of all matching nodes for a query, and throw an error if no elements match."]}),"\n",(0,t.jsxs)(n.h3,{id:"query-by",children:[(0,t.jsx)(n.code,{children:"queryBy*"})," queries"]}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"queryBy*"})," queries return the first matching node for a query, and return ",(0,t.jsx)(n.code,{children:"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 ",(0,t.jsx)(n.code,{children:"queryAllBy"})," instead)."]}),"\n",(0,t.jsxs)(n.h3,{id:"query-all-by",children:[(0,t.jsx)(n.code,{children:"queryAllBy*"})," queries"]}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"queryAllBy*"})," queries return an array of all matching nodes for a query, and return an empty array (",(0,t.jsx)(n.code,{children:"[]"}),") when no elements match."]}),"\n",(0,t.jsxs)(n.h3,{id:"find-by",children:[(0,t.jsx)(n.code,{children:"findBy*"})," queries"]}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"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 1000 ms. If you need to find more than one element, then use ",(0,t.jsx)(n.code,{children:"findAllBy*"}),"."]}),"\n",(0,t.jsxs)(n.h3,{id:"find-all-by",children:[(0,t.jsx)(n.code,{children:"findAllBy*"})," queries"]}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"findAllBy*"})," queries return a promise which resolves to an array of matching elements. The promise is rejected if no elements match after a default timeout of 1000 ms."]}),"\n",(0,t.jsx)(n.admonition,{type:"info",children:(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"findBy*"})," and ",(0,t.jsx)(n.code,{children:"findAllBy*"})," queries accept optional ",(0,t.jsx)(n.code,{children:"waitForOptions"})," object argument which can contain ",(0,t.jsx)(n.code,{children:"timeout"}),", ",(0,t.jsx)(n.code,{children:"interval"})," and ",(0,t.jsx)(n.code,{children:"onTimeout"})," properies which have the same meaning as respective options for ",(0,t.jsx)(n.a,{href:"api#waitfor",children:(0,t.jsx)(n.code,{children:"waitFor"})})," function."]})}),"\n",(0,t.jsx)(n.admonition,{type:"info",children:(0,t.jsxs)(n.p,{children:["In cases when your ",(0,t.jsx)(n.code,{children:"findBy*"})," and ",(0,t.jsx)(n.code,{children:"findAllBy*"})," queries throw when not able to find matching elements it is useful to pass ",(0,t.jsx)(n.code,{children:"onTimeout: () => { screen.debug(); }"})," callback using ",(0,t.jsx)(n.code,{children:"waitForOptions"})," parameter."]})}),"\n",(0,t.jsx)(n.admonition,{type:"info",children:(0,t.jsxs)(n.p,{children:["In order to properly use ",(0,t.jsx)(n.code,{children:"findBy*"})," and ",(0,t.jsx)(n.code,{children:"findAllBy*"})," queries you need at least React >=16.9.0 (featuring async ",(0,t.jsx)(n.code,{children:"act"}),") or React Native >=0.61 (which comes with React >=16.9.0)."]})}),"\n",(0,t.jsx)(n.h2,{id:"query-predicates",children:"Query Predicates"}),"\n",(0,t.jsx)(n.p,{children:(0,t.jsxs)(n.em,{children:["Note: most methods like this one return a ",(0,t.jsx)(n.a,{href:"https://reactjs.org/docs/test-renderer.html#testinstance",children:(0,t.jsx)(n.code,{children:"ReactTestInstance"})})," with following properties that you may be interested in:"]})}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-typescript",children:"type ReactTestInstance = {\n type: string | Function;\n props: { [propName: string]: any };\n parent: ReactTestInstance | null;\n children: Array;\n};\n"})}),"\n",(0,t.jsx)(n.h3,{id:"by-role",children:(0,t.jsx)(n.code,{children:"ByRole"})}),"\n",(0,t.jsxs)(n.blockquote,{children:["\n",(0,t.jsx)(n.p,{children:"getByRole, getAllByRole, queryByRole, queryAllByRole, findByRole, findAllByRole"}),"\n"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-ts",children:"getByRole(\n role: TextMatch,\n options?: {\n name?: TextMatch\n disabled?: boolean,\n selected?: boolean,\n checked?: boolean | 'mixed',\n busy?: boolean,\n expanded?: boolean,\n value: {\n min?: number;\n max?: number;\n now?: number;\n text?: TextMatch;\n },\n includeHiddenElements?: boolean;\n }\n): ReactTestInstance;\n"})}),"\n",(0,t.jsxs)(n.p,{children:["Returns a ",(0,t.jsx)(n.code,{children:"ReactTestInstance"})," with matching ",(0,t.jsx)(n.code,{children:"role"})," or ",(0,t.jsx)(n.code,{children:"accessibilityRole"})," prop."]}),"\n",(0,t.jsxs)(n.admonition,{type:"info",children:[(0,t.jsxs)(n.p,{children:["In order for ",(0,t.jsx)(n.code,{children:"*ByRole"})," queries to match an element it needs to be considered an accessibility element:"]}),(0,t.jsxs)(n.ol,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"Text"}),", ",(0,t.jsx)(n.code,{children:"TextInput"})," and ",(0,t.jsx)(n.code,{children:"Switch"})," host elements are these by default."]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"View"})," host elements need an explicit ",(0,t.jsx)(n.a,{href:"https://reactnative.dev/docs/accessibility#accessible",children:(0,t.jsx)(n.code,{children:"accessible"})})," prop set to ",(0,t.jsx)(n.code,{children:"true"})]}),"\n",(0,t.jsxs)(n.li,{children:["Some React Native composite components like ",(0,t.jsx)(n.code,{children:"Pressable"})," & ",(0,t.jsx)(n.code,{children:"TouchableOpacity"})," render host ",(0,t.jsx)(n.code,{children:"View"})," element with ",(0,t.jsx)(n.code,{children:"accessible"})," prop already set."]}),"\n"]})]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-jsx",children:"import { render, screen } from '@testing-library/react-native';\n\nrender(\n \n Hello\n ,\n);\nconst element = screen.getByRole('button');\nconst element2 = screen.getByRole('button', { name: 'Hello' });\nconst element3 = screen.getByRole('button', { name: 'Hello', disabled: true });\n"})}),"\n",(0,t.jsx)(n.h4,{id:"by-role-options",children:"Options"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"name"}),": Finds an element with given ",(0,t.jsx)(n.code,{children:"role"}),"/",(0,t.jsx)(n.code,{children:"accessibilityRole"})," and an accessible name (= accessability label or text content)."]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"disabled"}),": You can filter elements by their disabled state (coming either from ",(0,t.jsx)(n.code,{children:"aria-disabled"})," prop or ",(0,t.jsx)(n.code,{children:"accessbilityState.disabled"})," prop). The possible values are ",(0,t.jsx)(n.code,{children:"true"})," or ",(0,t.jsx)(n.code,{children:"false"}),". Querying ",(0,t.jsx)(n.code,{children:"disabled: false"})," will also match elements with ",(0,t.jsx)(n.code,{children:"disabled: undefined"})," (see the ",(0,t.jsx)(n.a,{href:"https://github.com/callstack/react-native-testing-library/wiki/Accessibility:-State",children:"wiki"})," for more details)."]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["See ",(0,t.jsx)(n.a,{href:"https://reactnative.dev/docs/accessibility#accessibilitystate",children:"React Native's accessibilityState"})," docs to learn more about the ",(0,t.jsx)(n.code,{children:"disabled"})," state."]}),"\n",(0,t.jsxs)(n.li,{children:["This option can alternatively be expressed using the ",(0,t.jsxs)(n.a,{href:"jest-matchers#tobeenabled",children:[(0,t.jsx)(n.code,{children:"toBeEnabled()"})," / ",(0,t.jsx)(n.code,{children:"toBeDisabled()"})]})," Jest matchers."]}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"selected"}),": You can filter elements by their selected state (coming either from ",(0,t.jsx)(n.code,{children:"aria-selected"})," prop or ",(0,t.jsx)(n.code,{children:"accessbilityState.selected"})," prop). The possible values are ",(0,t.jsx)(n.code,{children:"true"})," or ",(0,t.jsx)(n.code,{children:"false"}),". Querying ",(0,t.jsx)(n.code,{children:"selected: false"})," will also match elements with ",(0,t.jsx)(n.code,{children:"selected: undefined"})," (see the ",(0,t.jsx)(n.a,{href:"https://github.com/callstack/react-native-testing-library/wiki/Accessibility:-State",children:"wiki"})," for more details)."]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["See ",(0,t.jsx)(n.a,{href:"https://reactnative.dev/docs/accessibility#accessibilitystate",children:"React Native's accessibilityState"})," docs to learn more about the ",(0,t.jsx)(n.code,{children:"selected"})," state."]}),"\n",(0,t.jsxs)(n.li,{children:["This option can alternatively be expressed using the ",(0,t.jsx)(n.a,{href:"jest-matchers#tobeselected",children:(0,t.jsx)(n.code,{children:"toBeSelected()"})})," Jest matcher."]}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"checked"}),": You can filter elements by their checked state (coming either from ",(0,t.jsx)(n.code,{children:"aria-checked"})," prop or ",(0,t.jsx)(n.code,{children:"accessbilityState.checked"})," prop). The possible values are ",(0,t.jsx)(n.code,{children:"true"}),", ",(0,t.jsx)(n.code,{children:"false"}),", or ",(0,t.jsx)(n.code,{children:'"mixed"'}),"."]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["See ",(0,t.jsx)(n.a,{href:"https://reactnative.dev/docs/accessibility#accessibilitystate",children:"React Native's accessibilityState"})," docs to learn more about the ",(0,t.jsx)(n.code,{children:"checked"})," state."]}),"\n",(0,t.jsxs)(n.li,{children:["This option can alternatively be expressed using the ",(0,t.jsxs)(n.a,{href:"jest-matchers#tobechecked",children:[(0,t.jsx)(n.code,{children:"toBeChecked()"})," / ",(0,t.jsx)(n.code,{children:"toBePartiallyChecked()"})]})," Jest matchers."]}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"busy"}),": You can filter elements by their busy state (coming either from ",(0,t.jsx)(n.code,{children:"aria-busy"})," prop or ",(0,t.jsx)(n.code,{children:"accessbilityState.busy"})," prop). The possible values are ",(0,t.jsx)(n.code,{children:"true"})," or ",(0,t.jsx)(n.code,{children:"false"}),". Querying ",(0,t.jsx)(n.code,{children:"busy: false"})," will also match elements with ",(0,t.jsx)(n.code,{children:"busy: undefined"})," (see the ",(0,t.jsx)(n.a,{href:"https://github.com/callstack/react-native-testing-library/wiki/Accessibility:-State",children:"wiki"})," for more details)."]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["See ",(0,t.jsx)(n.a,{href:"https://reactnative.dev/docs/accessibility#accessibilitystate",children:"React Native's accessibilityState"})," docs to learn more about the ",(0,t.jsx)(n.code,{children:"busy"})," state."]}),"\n",(0,t.jsxs)(n.li,{children:["This option can alternatively be expressed using the ",(0,t.jsx)(n.a,{href:"jest-matchers#tobebusy",children:(0,t.jsx)(n.code,{children:"toBeBusy()"})})," Jest matcher."]}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"expanded"}),": You can filter elements by their expanded state (coming either from ",(0,t.jsx)(n.code,{children:"aria-expanded"})," prop or ",(0,t.jsx)(n.code,{children:"accessbilityState.expanded"})," prop). The possible values are ",(0,t.jsx)(n.code,{children:"true"})," or ",(0,t.jsx)(n.code,{children:"false"}),"."]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["See ",(0,t.jsx)(n.a,{href:"https://reactnative.dev/docs/accessibility#accessibilitystate",children:"React Native's accessibilityState"})," docs to learn more about the ",(0,t.jsx)(n.code,{children:"expanded"})," state."]}),"\n",(0,t.jsxs)(n.li,{children:["This option can alternatively be expressed using the ",(0,t.jsxs)(n.a,{href:"jest-matchers#tobeexpanded",children:[(0,t.jsx)(n.code,{children:"toBeExpanded()"})," / ",(0,t.jsx)(n.code,{children:"toBeCollapsed()"})]})," Jest matchers."]}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:["\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"value"}),": Filter elements by their accessibility value, based on either ",(0,t.jsx)(n.code,{children:"aria-valuemin"}),", ",(0,t.jsx)(n.code,{children:"aria-valuemax"}),", ",(0,t.jsx)(n.code,{children:"aria-valuenow"}),", ",(0,t.jsx)(n.code,{children:"aria-valuetext"})," or ",(0,t.jsx)(n.code,{children:"accessibilityValue"})," props. Accessiblity value conceptually consists of numeric ",(0,t.jsx)(n.code,{children:"min"}),", ",(0,t.jsx)(n.code,{children:"max"})," and ",(0,t.jsx)(n.code,{children:"now"})," entries, as well as string ",(0,t.jsx)(n.code,{children:"text"})," entry."]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["See React Native ",(0,t.jsx)(n.a,{href:"https://reactnative.dev/docs/accessibility#accessibilityvalue",children:"accessibilityValue"})," docs to learn more about the accessibility value concept."]}),"\n",(0,t.jsxs)(n.li,{children:["This option can alternatively be expressed using the ",(0,t.jsx)(n.a,{href:"jest-matchers#tohaveaccessibilityvalue",children:(0,t.jsx)(n.code,{children:"toHaveAccessibilityValue()"})})," Jest matcher."]}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,t.jsx)(n.h3,{id:"by-text",children:(0,t.jsx)(n.code,{children:"ByText"})}),"\n",(0,t.jsxs)(n.blockquote,{children:["\n",(0,t.jsx)(n.p,{children:"getByText, getAllByText, queryByText, queryAllByText, findByText, findAllByText"}),"\n"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-ts",children:"getByText(\n text: TextMatch,\n options?: {\n exact?: boolean;\n normalizer?: (text: string) => string;\n includeHiddenElements?: boolean;\n }\n): ReactTestInstance;\n"})}),"\n",(0,t.jsxs)(n.p,{children:["Returns a ",(0,t.jsx)(n.code,{children:"ReactTestInstance"})," with matching text \u2013 may be a string or regular expression."]}),"\n",(0,t.jsxs)(n.p,{children:["This method will join ",(0,t.jsx)(n.code,{children:""})," siblings to find matches, similarly to ",(0,t.jsx)(n.a,{href:"https://reactnative.dev/docs/text#containers",children:"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."]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-jsx",children:"import { render, screen } from '@testing-library/react-native';\n\nrender();\nconst element = screen.getByText('banana');\n"})}),"\n",(0,t.jsx)(n.h3,{id:"by-placeholder-text",children:(0,t.jsx)(n.code,{children:"ByPlaceholderText"})}),"\n",(0,t.jsxs)(n.blockquote,{children:["\n",(0,t.jsx)(n.p,{children:"getByPlaceholderText, getAllByPlaceholderText, queryByPlaceholderText, queryAllByPlaceholderText, findByPlaceholderText, findAllByPlaceholderText"}),"\n"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-ts",children:"getByPlaceholderText(\n text: TextMatch,\n options?: {\n exact?: boolean;\n normalizer?: (text: string) => string;\n includeHiddenElements?: boolean;\n }\n): ReactTestInstance;\n"})}),"\n",(0,t.jsxs)(n.p,{children:["Returns a ",(0,t.jsx)(n.code,{children:"ReactTestInstance"})," for a ",(0,t.jsx)(n.code,{children:"TextInput"})," with a matching placeholder \u2013 may be a string or regular expression."]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-jsx",children:"import { render, screen } from '@testing-library/react-native';\n\nrender();\nconst element = screen.getByPlaceholderText('username');\n"})}),"\n",(0,t.jsx)(n.h3,{id:"by-display-value",children:(0,t.jsx)(n.code,{children:"ByDisplayValue"})}),"\n",(0,t.jsxs)(n.blockquote,{children:["\n",(0,t.jsx)(n.p,{children:"getByDisplayValue, getAllByDisplayValue, queryByDisplayValue, queryAllByDisplayValue, findByDisplayValue, findAllByDisplayValue"}),"\n"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-ts",children:"getByDisplayValue(\n value: TextMatch,\n options?: {\n exact?: boolean;\n normalizer?: (text: string) => string;\n includeHiddenElements?: boolean;\n },\n): ReactTestInstance;\n"})}),"\n",(0,t.jsxs)(n.p,{children:["Returns a ",(0,t.jsx)(n.code,{children:"ReactTestInstance"})," for a ",(0,t.jsx)(n.code,{children:"TextInput"})," with a matching display value \u2013 may be a string or regular expression."]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-jsx",children:"import { render, screen } from '@testing-library/react-native';\n\nrender();\nconst element = screen.getByDisplayValue('username');\n"})}),"\n",(0,t.jsx)(n.h3,{id:"by-test-id",children:(0,t.jsx)(n.code,{children:"ByTestId"})}),"\n",(0,t.jsxs)(n.blockquote,{children:["\n",(0,t.jsx)(n.p,{children:"getByTestId, getAllByTestId, queryByTestId, queryAllByTestId, findByTestId, findAllByTestId"}),"\n"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-ts",children:"getByTestId(\n testId: TextMatch,\n options?: {\n exact?: boolean;\n normalizer?: (text: string) => string;\n includeHiddenElements?: boolean;\n },\n): ReactTestInstance;\n"})}),"\n",(0,t.jsxs)(n.p,{children:["Returns a ",(0,t.jsx)(n.code,{children:"ReactTestInstance"})," with matching ",(0,t.jsx)(n.code,{children:"testID"})," prop. ",(0,t.jsx)(n.code,{children:"testID"})," \u2013 may be a string or a regular expression."]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-jsx",children:"import { render, screen } from '@testing-library/react-native';\n\nrender();\nconst element = screen.getByTestId('unique-id');\n"})}),"\n",(0,t.jsx)(n.admonition,{type:"info",children:(0,t.jsxs)(n.p,{children:["In the spirit of ",(0,t.jsx)(n.a,{href:"https://testing-library.com/docs/guiding-principles",children:"the guiding principles"}),", it is recommended to use this only after the other queries don't work for your use case. Using ",(0,t.jsx)(n.code,{children:"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 ",(0,t.jsx)(n.a,{href:"https://kentcdodds.com/blog/making-your-ui-tests-resilient-to-change",children:'"Making your UI tests resilient to change"'}),"."]})}),"\n",(0,t.jsx)(n.h3,{id:"by-label-text",children:(0,t.jsx)(n.code,{children:"ByLabelText"})}),"\n",(0,t.jsxs)(n.blockquote,{children:["\n",(0,t.jsx)(n.p,{children:"getByLabelText, getAllByLabelText, queryByLabelText, queryAllByLabelText, findByLabelText, findAllByLabelText"}),"\n"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-ts",children:"getByLabelText(\n text: TextMatch,\n options?: {\n exact?: boolean;\n normalizer?: (text: string) => string;\n includeHiddenElements?: boolean;\n },\n): ReactTestInstance;\n"})}),"\n",(0,t.jsxs)(n.p,{children:["Returns a ",(0,t.jsx)(n.code,{children:"ReactTestInstance"})," with matching label:"]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["either by matching ",(0,t.jsx)(n.a,{href:"https://reactnative.dev/docs/accessibility#aria-label",children:(0,t.jsx)(n.code,{children:"aria-label"})}),"/",(0,t.jsx)(n.a,{href:"https://reactnative.dev/docs/accessibility#accessibilitylabel",children:(0,t.jsx)(n.code,{children:"accessibilityLabel"})})," prop"]}),"\n",(0,t.jsxs)(n.li,{children:["or by matching text content of view referenced by ",(0,t.jsx)(n.a,{href:"https://reactnative.dev/docs/accessibility#aria-labelledby-android",children:(0,t.jsx)(n.code,{children:"aria-labelledby"})}),"/",(0,t.jsx)(n.a,{href:"https://reactnative.dev/docs/accessibility#accessibilitylabelledby-android",children:(0,t.jsx)(n.code,{children:"accessibilityLabelledBy"})})," prop"]}),"\n"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-jsx",children:"import { render, screen } from '@testing-library/react-native';\n\nrender();\nconst element = screen.getByLabelText('my-label');\n"})}),"\n",(0,t.jsxs)(n.h3,{id:"by-hint-text",children:[(0,t.jsx)(n.code,{children:"ByHintText"}),", ",(0,t.jsx)(n.code,{children:"ByA11yHint"}),", ",(0,t.jsx)(n.code,{children:"ByAccessibilityHint"})]}),"\n",(0,t.jsxs)(n.blockquote,{children:["\n",(0,t.jsx)(n.p,{children:"getByA11yHint, getAllByA11yHint, queryByA11yHint, queryAllByA11yHint, findByA11yHint, findAllByA11yHint\ngetByAccessibilityHint, getAllByAccessibilityHint, queryByAccessibilityHint, queryAllByAccessibilityHint, findByAccessibilityHint, findAllByAccessibilityHint\ngetByHintText, getAllByHintText, queryByHintText, queryAllByHintText, findByHintText, findAllByHintText"}),"\n"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-ts",children:"getByHintText(\n hint: TextMatch,\n options?: {\n exact?: boolean;\n normalizer?: (text: string) => string;\n includeHiddenElements?: boolean;\n },\n): ReactTestInstance;\n"})}),"\n",(0,t.jsxs)(n.p,{children:["Returns a ",(0,t.jsx)(n.code,{children:"ReactTestInstance"})," with matching ",(0,t.jsx)(n.code,{children:"accessibilityHint"})," prop."]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-jsx",children:"import { render, screen } from '@testing-library/react-native';\n\nrender();\nconst element = screen.getByHintText('Plays a song');\n"})}),"\n",(0,t.jsx)(n.admonition,{type:"info",children:(0,t.jsxs)(n.p,{children:["Please consult ",(0,t.jsxs)(n.a,{href:"https://developer.apple.com/documentation/objectivec/nsobject/1615093-accessibilityhint",children:["Apple guidelines on how ",(0,t.jsx)(n.code,{children:"accessibilityHint"})," should be used"]}),"."]})}),"\n",(0,t.jsxs)(n.h3,{id:"by-accessibility-state",children:[(0,t.jsx)(n.code,{children:"ByA11yState"}),", ",(0,t.jsx)(n.code,{children:"ByAccessibilityState"})," (deprecated)"]}),"\n",(0,t.jsxs)(n.admonition,{type:"caution",children:[(0,t.jsx)(n.p,{children:"This query has been marked deprecated, as is typically too general to give meaningful results. Therefore, it's better to use one of following options:"}),(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.a,{href:"#by-role",children:(0,t.jsx)(n.code,{children:"*ByRole"})})," query with relevant state options: ",(0,t.jsx)(n.code,{children:"disabled"}),", ",(0,t.jsx)(n.code,{children:"selected"}),", ",(0,t.jsx)(n.code,{children:"checked"}),", ",(0,t.jsx)(n.code,{children:"expanded"})," and ",(0,t.jsx)(n.code,{children:"busy"})]}),"\n",(0,t.jsxs)(n.li,{children:["use built-in Jest matchers to check the state of element found using some other query:","\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["enabled state: ",(0,t.jsxs)(n.a,{href:"jest-matchers#tobeenabled",children:[(0,t.jsx)(n.code,{children:"toBeEnabled()"})," / ",(0,t.jsx)(n.code,{children:"toBeDisabled()"})]})]}),"\n",(0,t.jsxs)(n.li,{children:["checked state: ",(0,t.jsxs)(n.a,{href:"jest-matchers#tobechecked",children:[(0,t.jsx)(n.code,{children:"toBeChecked()"})," / ",(0,t.jsx)(n.code,{children:"toBePartiallyChecked()"})]})]}),"\n",(0,t.jsxs)(n.li,{children:["selected state: ",(0,t.jsx)(n.a,{href:"jest-matchers#tobeselected",children:(0,t.jsx)(n.code,{children:"toBeSelected()"})})]}),"\n",(0,t.jsxs)(n.li,{children:["expanded state: ",(0,t.jsxs)(n.a,{href:"jest-matchers#tobeexpanded",children:[(0,t.jsx)(n.code,{children:"toBeExpanded()"})," / ",(0,t.jsx)(n.code,{children:"toBeCollapsed()"})]})]}),"\n",(0,t.jsxs)(n.li,{children:["busy state: ",(0,t.jsx)(n.a,{href:"jest-matchers#tobebusy",children:(0,t.jsx)(n.code,{children:"toBeBusy()"})})]}),"\n"]}),"\n"]}),"\n"]})]}),"\n",(0,t.jsxs)(n.blockquote,{children:["\n",(0,t.jsx)(n.p,{children:"getByA11yState, getAllByA11yState, queryByA11yState, queryAllByA11yState, findByA11yState, findAllByA11yState\ngetByAccessibilityState, getAllByAccessibilityState, queryByAccessibilityState, queryAllByAccessibilityState, findByAccessibilityState, findAllByAccessibilityState"}),"\n"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-ts",children:"getByA11yState(\n state: {\n disabled?: boolean,\n selected?: boolean,\n checked?: boolean | 'mixed',\n busy?: boolean,\n expanded?: boolean,\n },\n options?: {\n includeHiddenElements?: boolean;\n },\n): ReactTestInstance;\n"})}),"\n",(0,t.jsxs)(n.p,{children:["Returns a ",(0,t.jsx)(n.code,{children:"ReactTestInstance"})," with matching ",(0,t.jsx)(n.code,{children:"accessibilityState"})," prop or ARIA state props: ",(0,t.jsx)(n.code,{children:"aria-disabled"}),", ",(0,t.jsx)(n.code,{children:"aria-selected"}),", ",(0,t.jsx)(n.code,{children:"aria-checked"}),", ",(0,t.jsx)(n.code,{children:"aria-busy"}),", and ",(0,t.jsx)(n.code,{children:"aria-expanded"}),"."]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-jsx",children:"import { render, screen } from '@testing-library/react-native';\n\nrender();\nconst element = screen.getByA11yState({ disabled: true });\n"})}),"\n",(0,t.jsxs)(n.admonition,{type:"note",children:[(0,t.jsxs)(n.h4,{id:"default-state-for-disabled-selected-and-busy-keys",children:["Default state for: ",(0,t.jsx)(n.code,{children:"disabled"}),", ",(0,t.jsx)(n.code,{children:"selected"}),", and ",(0,t.jsx)(n.code,{children:"busy"})," keys"]}),(0,t.jsxs)(n.p,{children:["Passing ",(0,t.jsx)(n.code,{children:"false"})," matcher value will match both elements with explicit ",(0,t.jsx)(n.code,{children:"false"})," state value and without explicit state value."]}),(0,t.jsxs)(n.p,{children:["For instance, ",(0,t.jsx)(n.code,{children:"getByA11yState({ disabled: false })"})," will match elements with following props:"]}),(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.code,{children:"accessibilityState={{ disabled: false, ... }}"})}),"\n",(0,t.jsxs)(n.li,{children:["no ",(0,t.jsx)(n.code,{children:"disabled"})," key under ",(0,t.jsx)(n.code,{children:"accessibilityState"})," prop, e.g. ",(0,t.jsx)(n.code,{children:"accessibilityState={{}}"})]}),"\n",(0,t.jsxs)(n.li,{children:["no ",(0,t.jsx)(n.code,{children:"accessibilityState"})," prop at all"]}),"\n"]}),(0,t.jsxs)(n.h4,{id:"default-state-for-checked-and-expanded-keys",children:["Default state for: ",(0,t.jsx)(n.code,{children:"checked"})," and ",(0,t.jsx)(n.code,{children:"expanded"})," keys"]}),(0,t.jsxs)(n.p,{children:["Passing ",(0,t.jsx)(n.code,{children:"false"})," matcher value will only match elements with explicit ",(0,t.jsx)(n.code,{children:"false"})," state value."]}),(0,t.jsxs)(n.p,{children:["For instance, ",(0,t.jsx)(n.code,{children:"getByA11yState({ checked: false })"})," will only match elements with:"]}),(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:(0,t.jsx)(n.code,{children:"accessibilityState={{ checked: false, ... }}"})}),"\n"]}),(0,t.jsx)(n.p,{children:"but will not match elements with following props:"}),(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["no ",(0,t.jsx)(n.code,{children:"checked"})," key under ",(0,t.jsx)(n.code,{children:"accessibilityState"})," prop, e.g. ",(0,t.jsx)(n.code,{children:"accessibilityState={{}}"})]}),"\n",(0,t.jsxs)(n.li,{children:["no ",(0,t.jsx)(n.code,{children:"accessibilityState"})," prop at all"]}),"\n"]}),(0,t.jsx)(n.p,{children:"The difference in handling default values is made to reflect observed accessibility behaviour on iOS and Android platforms."})]}),"\n",(0,t.jsxs)(n.h3,{id:"by-accessibility-value",children:[(0,t.jsx)(n.code,{children:"ByA11yValue"}),", ",(0,t.jsx)(n.code,{children:"ByAccessibilityValue"})," (deprecated)"]}),"\n",(0,t.jsxs)(n.admonition,{type:"caution",children:[(0,t.jsx)(n.p,{children:"This query has been marked deprecated, as is typically too general to give meaningful results. Therefore, it's better to use one of following options:"}),(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.a,{href:"jest-matchers#tohaveaccessibilityvalue",children:(0,t.jsx)(n.code,{children:"toHaveAccessibilityValue()"})})," Jest matcher to check the state of element found using some other query"]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.a,{href:"#by-role",children:(0,t.jsx)(n.code,{children:"*ByRole"})})," query with ",(0,t.jsx)(n.code,{children:"value"})," option"]}),"\n"]})]}),"\n",(0,t.jsxs)(n.blockquote,{children:["\n",(0,t.jsx)(n.p,{children:"getByA11yValue, getAllByA11yValue, queryByA11yValue, queryAllByA11yValue, findByA11yValue, findAllByA11yValue\ngetByAccessibilityValue, getAllByAccessibilityValue, queryByAccessibilityValue, queryAllByAccessibilityValue, findByAccessibilityValue, findAllByAccessibilityValue"}),"\n"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-ts",children:"getByA11yValue(\n value: {\n min?: number;\n max?: number;\n now?: number;\n text?: TextMatch;\n },\n options?: {\n includeHiddenElements?: boolean;\n },\n): ReactTestInstance;\n"})}),"\n",(0,t.jsxs)(n.p,{children:["Returns a host element with matching accessibility value based on ",(0,t.jsx)(n.code,{children:"aria-valuemin"}),", ",(0,t.jsx)(n.code,{children:"aria-valuemax"}),", ",(0,t.jsx)(n.code,{children:"aria-valuenow"}),", ",(0,t.jsx)(n.code,{children:"aria-valuetext"})," & ",(0,t.jsx)(n.code,{children:"accessibilityValue"})," props. Only value entires provided to the query will be used to match elements. Element might have additional accessibility value entries and still be matched."]}),"\n",(0,t.jsxs)(n.p,{children:["When querying by ",(0,t.jsx)(n.code,{children:"text"})," entry a string or regex might be used."]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-jsx",children:"import { render, screen } from '@testing-library/react-native';\n\nrender();\nconst element = screen.getByA11yValue({ now: 25 });\nconst element2 = screen.getByA11yValue({ text: /25/ });\n"})}),"\n",(0,t.jsx)(n.h3,{id:"common-options",children:"Common options"}),"\n",(0,t.jsxs)(n.p,{children:["Usually query first argument can be a ",(0,t.jsx)(n.strong,{children:"string"})," or a ",(0,t.jsx)(n.strong,{children:"regex"}),". All queries take at least the ",(0,t.jsx)(n.a,{href:"#hidden-option",children:(0,t.jsx)(n.code,{children:"hidden"})})," option as an optionnal second argument and some queries accept more options which change string matching behaviour. See ",(0,t.jsx)(n.a,{href:"#textmatch",children:"TextMatch"})," for more info."]}),"\n",(0,t.jsxs)(n.h4,{id:"includehiddenelements-option",children:[(0,t.jsx)(n.code,{children:"includeHiddenElements"})," option"]}),"\n",(0,t.jsxs)(n.p,{children:["All queries have the ",(0,t.jsx)(n.code,{children:"includeHiddenElements"})," option which affects whether ",(0,t.jsx)(n.a,{href:"/react-native-testing-library/docs/api#ishiddenfromaccessibility",children:"elements hidden from accessibility"})," are matched by the query. By default queries will not match hidden elements, because the users of the app would not be able to see such elements."]}),"\n",(0,t.jsxs)(n.p,{children:["You can configure the default value with the ",(0,t.jsxs)(n.a,{href:"/react-native-testing-library/docs/api#configure",children:[(0,t.jsx)(n.code,{children:"configure"})," function"]}),"."]}),"\n",(0,t.jsxs)(n.p,{children:["This option is also available as ",(0,t.jsx)(n.code,{children:"hidden"})," alias for compatibility with ",(0,t.jsx)(n.a,{href:"https://testing-library.com/docs/queries/byrole#hidden",children:"React Testing Library"}),"."]}),"\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.strong,{children:"Examples"})}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-tsx",children:"render(Hidden from accessibility);\n\n// Exclude hidden elements\nexpect(\n screen.queryByText('Hidden from accessibility', {\n includeHiddenElements: false,\n }),\n).not.toBeOnTheScreen();\n\n// Include hidden elements\nexpect(screen.getByText('Hidden from accessibility')).toBeOnTheScreen();\nexpect(\n screen.getByText('Hidden from accessibility', { includeHiddenElements: true }),\n).toBeOnTheScreen();\n"})}),"\n",(0,t.jsx)(n.h2,{id:"textmatch-type",children:"TextMatch type"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-ts",children:"type TextMatch = string | RegExp;\n"})}),"\n",(0,t.jsxs)(n.p,{children:["Most of the query APIs take a ",(0,t.jsx)(n.code,{children:"TextMatch"})," as an argument, which means the argument can be either a ",(0,t.jsx)(n.em,{children:"string"})," or ",(0,t.jsx)(n.em,{children:"regex"}),"."]}),"\n",(0,t.jsx)(n.h3,{id:"examples",children:"Examples"}),"\n",(0,t.jsx)(n.p,{children:"Given the following render:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-jsx",children:"render(Hello World);\n"})}),"\n",(0,t.jsxs)(n.p,{children:["Will ",(0,t.jsx)(n.strong,{children:"find a match"}),":"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-js",children:"// Matching a string:\nscreen.getByText('Hello World'); // full string match\nscreen.getByText('llo Worl', { exact: false }); // substring match\nscreen.getByText('hello world', { exact: false }); // ignore case-sensitivity\n\n// Matching a regex:\nscreen.getByText(/World/); // substring match\nscreen.getByText(/world/i); // substring match, ignore case\nscreen.getByText(/^hello world$/i); // full string match, ignore case-sensitivity\nscreen.getByText(/Hello W?oRlD/i); // advanced regex\n"})}),"\n",(0,t.jsxs)(n.p,{children:["Will ",(0,t.jsx)(n.strong,{children:"NOT find a match"})]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-js",children:"// substring does not match\nscreen.getByText('llo Worl');\n// full string does not match\nscreen.getByText('Goodbye World');\n\n// case-sensitive regex with different case\nscreen.getByText(/hello world/);\n"})}),"\n",(0,t.jsx)(n.h3,{id:"text-match-options",children:"Options"}),"\n",(0,t.jsx)(n.h4,{id:"precision",children:"Precision"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-typescript",children:"type TextMatchOptions = {\n exact?: boolean;\n normalizer?: (text: string) => string;\n};\n"})}),"\n",(0,t.jsxs)(n.p,{children:["Queries that take a ",(0,t.jsx)(n.code,{children:"TextMatch"})," also accept an object as the second argument that can contain options that affect the precision of string matching:"]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"exact"}),": Defaults to ",(0,t.jsx)(n.code,{children:"true"}),"; matches full strings, case-sensitive. When false, matches substrings and is not case-sensitive.","\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"exact"})," has no effect on regex argument."]}),"\n",(0,t.jsxs)(n.li,{children:["In most cases using a ",(0,t.jsx)(n.code,{children:"regex"})," instead of a string gives you more control over fuzzy matching and should be preferred over ",(0,t.jsx)(n.code,{children:"{ exact: false }"}),"."]}),"\n"]}),"\n"]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"normalizer"}),": An optional function which overrides normalization behavior. See ",(0,t.jsx)(n.a,{href:"#normalization",children:"Normalization"}),"."]}),"\n"]}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"exact"})," option defaults to ",(0,t.jsx)(n.code,{children:"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."]}),"\n",(0,t.jsx)(n.h4,{id:"normalization",children:"Normalization"}),"\n",(0,t.jsx)(n.p,{children:"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."}),"\n",(0,t.jsxs)(n.p,{children:["If you want to prevent that normalization, or provide alternative normalization (e.g. to remove Unicode control characters), you can provide a ",(0,t.jsx)(n.code,{children:"normalizer"})," function in the options object. This function will be given a string and is expected to return a normalized version of that string."]}),"\n",(0,t.jsx)(n.admonition,{type:"info",children:(0,t.jsxs)(n.p,{children:["Specifying a value for ",(0,t.jsx)(n.code,{children:"normalizer"})," replaces the built-in normalization, but you can call ",(0,t.jsx)(n.code,{children:"getDefaultNormalizer"})," to obtain a built-in normalizer, either to adjust that normalization or to call it from your own normalizer."]})}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"getDefaultNormalizer"})," take options object which allows the selection of behaviour:"]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"trim"}),": Defaults to ",(0,t.jsx)(n.code,{children:"true"}),". Trims leading and trailing whitespace."]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"collapseWhitespace"}),": Defaults to ",(0,t.jsx)(n.code,{children:"true"}),". Collapses inner whitespace (newlines, tabs repeated spaces) into a single space."]}),"\n"]}),"\n",(0,t.jsx)(n.h5,{id:"normalization-examples",children:"Normalization Examples"}),"\n",(0,t.jsx)(n.p,{children:"To perform a match against text without trimming:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-typescript",children:"screen.getByText(node, 'text', {\n normalizer: getDefaultNormalizer({ trim: false }),\n});\n"})}),"\n",(0,t.jsx)(n.p,{children:"To override normalization to remove some Unicode characters whilst keeping some (but not all) of the built-in normalization behavior:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-typescript",children:"screen.getByText(node, 'text', {\n normalizer: (str) => getDefaultNormalizer({ trim: false })(str).replace(/[\\u200E-\\u200F]*/g, ''),\n});\n"})}),"\n",(0,t.jsx)(n.h2,{id:"legacy-unit-testing-helpers",children:"Legacy unit testing helpers"}),"\n",(0,t.jsxs)(n.blockquote,{children:["\n",(0,t.jsx)(n.p,{children:"Use sparingly and responsibly, escape hatches here"}),"\n"]}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"render"})," from ",(0,t.jsx)(n.code,{children:"@testing-library/react-native"})," exposes additional queries that ",(0,t.jsx)(n.strong,{children:"should not be used in component integration testing"}),", but some users (like component library creators) interested in unit testing some components may find helpful."]}),"\n",(0,t.jsxs)(i,{children:[(0,t.jsx)("summary",{children:"Queries helpful in unit testing"}),(0,t.jsx)(n.p,{children:"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."}),(0,t.jsx)(n.h3,{id:"unsafe_bytype",children:(0,t.jsx)(n.code,{children:"UNSAFE_ByType"})}),(0,t.jsxs)(n.blockquote,{children:["\n",(0,t.jsx)(n.p,{children:"UNSAFE_getByType, UNSAFE_getAllByType, UNSAFE_queryByType, UNSAFE_queryAllByType"}),"\n"]}),(0,t.jsxs)(n.p,{children:["Returns a ",(0,t.jsx)(n.code,{children:"ReactTestInstance"})," with matching a React component type."]}),(0,t.jsx)(n.admonition,{type:"caution",children:(0,t.jsx)(n.p,{children:"This query has been marked unsafe, since it requires knowledge about implementation details of the component. Use responsibly."})}),(0,t.jsx)(n.h3,{id:"unsafe_byprops",children:(0,t.jsx)(n.code,{children:"UNSAFE_ByProps"})}),(0,t.jsxs)(n.blockquote,{children:["\n",(0,t.jsx)(n.p,{children:"UNSAFE_getByProps, UNSAFE_getAllByProps, UNSAFE_queryByProps, UNSAFE_queryAllByProps"}),"\n"]}),(0,t.jsxs)(n.p,{children:["Returns a ",(0,t.jsx)(n.code,{children:"ReactTestInstance"})," with matching props object."]}),(0,t.jsx)(n.admonition,{type:"caution",children:(0,t.jsx)(n.p,{children:"This query has been marked unsafe, since it requires knowledge about implementation details of the component. Use responsibly."})})]})]})}function x(e={}){const{wrapper:n}={...(0,s.a)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(h,{...e})}):h(e)}},1151:(e,n,i)=>{i.d(n,{Z:()=>r,a:()=>c});var t=i(7294);const s={},l=t.createContext(s);function c(e){const n=t.useContext(l);return t.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function r(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:c(e.components),t.createElement(l.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/add06ab1.a1119996.js b/assets/js/add06ab1.50727a9c.js similarity index 55% rename from assets/js/add06ab1.a1119996.js rename to assets/js/add06ab1.50727a9c.js index f96fc228..f750b48c 100644 --- a/assets/js/add06ab1.a1119996.js +++ b/assets/js/add06ab1.50727a9c.js @@ -1 +1 @@ -"use strict";(self.webpackChunkreact_native_testing_library_website=self.webpackChunkreact_native_testing_library_website||[]).push([[725],{2063:(e,t,n)=>{n.d(t,{Z:()=>s});n(7294);var i=n(1351);const a={tableOfContentsInline:"tableOfContentsInline_prmo"};var r=n(5893);function s(e){let{toc:t,minHeadingLevel:n,maxHeadingLevel:s}=e;return(0,r.jsx)("div",{className:a.tableOfContentsInline,children:(0,r.jsx)(i.Z,{toc:t,minHeadingLevel:n,maxHeadingLevel:s,className:"table-of-contents",linkClassName:null})})}},1351:(e,t,n)=>{n.d(t,{Z:()=>m});var i=n(7294),a=n(6793);function r(e){const t=e.map((e=>({...e,parentIndex:-1,children:[]}))),n=Array(7).fill(-1);t.forEach(((e,t)=>{const i=n.slice(2,e.level);e.parentIndex=Math.max(...i),n[e.level]=t}));const i=[];return t.forEach((e=>{const{parentIndex:n,...a}=e;n>=0?t[n].children.push(a):i.push(a)})),i}function s(e){let{toc:t,minHeadingLevel:n,maxHeadingLevel:i}=e;return t.flatMap((e=>{const t=s({toc:e.children,minHeadingLevel:n,maxHeadingLevel:i});return function(e){return e.level>=n&&e.level<=i}(e)?[{...e,children:t}]:t}))}function l(e){const t=e.getBoundingClientRect();return t.top===t.bottom?l(e.parentNode):t}function o(e,t){var n;let{anchorTopOffset:i}=t;const a=e.find((e=>l(e).top>=i));if(a){var r;return function(e){return e.top>0&&e.bottom{e.current=t?0:document.querySelector(".navbar").clientHeight}),[t]),e}function d(e){const t=(0,i.useRef)(void 0),n=c();(0,i.useEffect)((()=>{if(!e)return()=>{};const{linkClassName:i,linkActiveClassName:a,minHeadingLevel:r,maxHeadingLevel:s}=e;function l(){const e=function(e){return Array.from(document.getElementsByClassName(e))}(i),l=function(e){let{minHeadingLevel:t,maxHeadingLevel:n}=e;const i=[];for(let a=t;a<=n;a+=1)i.push("h"+a+".anchor");return Array.from(document.querySelectorAll(i.join()))}({minHeadingLevel:r,maxHeadingLevel:s}),c=o(l,{anchorTopOffset:n.current}),d=e.find((e=>c&&c.id===function(e){return decodeURIComponent(e.href.substring(e.href.indexOf("#")+1))}(e)));e.forEach((e=>{!function(e,n){n?(t.current&&t.current!==e&&t.current.classList.remove(a),e.classList.add(a),t.current=e):e.classList.remove(a)}(e,e===d)}))}return document.addEventListener("scroll",l),document.addEventListener("resize",l),l(),()=>{document.removeEventListener("scroll",l),document.removeEventListener("resize",l)}}),[e,n])}var u=n(8746),h=n(5893);function g(e){let{toc:t,className:n,linkClassName:i,isChild:a}=e;return t.length?(0,h.jsx)("ul",{className:a?void 0:n,children:t.map((e=>(0,h.jsxs)("li",{children:[(0,h.jsx)(u.Z,{to:"#"+e.id,className:null!=i?i:void 0,dangerouslySetInnerHTML:{__html:e.value}}),(0,h.jsx)(g,{isChild:!0,toc:e.children,className:n,linkClassName:i})]},e.id)))}):null}const p=i.memo(g);function m(e){let{toc:t,className:n="table-of-contents table-of-contents__left-border",linkClassName:l="table-of-contents__link",linkActiveClassName:o,minHeadingLevel:c,maxHeadingLevel:u,...g}=e;const m=(0,a.L)(),v=null!=c?c:m.tableOfContents.minHeadingLevel,f=null!=u?u:m.tableOfContents.maxHeadingLevel,x=function(e){let{toc:t,minHeadingLevel:n,maxHeadingLevel:a}=e;return(0,i.useMemo)((()=>s({toc:r(t),minHeadingLevel:n,maxHeadingLevel:a})),[t,n,a])}({toc:t,minHeadingLevel:v,maxHeadingLevel:f});return d((0,i.useMemo)((()=>{if(l&&o)return{linkClassName:l,linkActiveClassName:o,minHeadingLevel:v,maxHeadingLevel:f}}),[l,o,v,f])),(0,h.jsx)(p,{toc:x,className:n,linkClassName:l,...g})}},818:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>l,default:()=>h,frontMatter:()=>s,metadata:()=>o,toc:()=>d});var i=n(5893),a=n(1151),r=n(2063);const s={id:"migration-v11",title:"Migration to 11.0"},l="Breaking changes",o={id:"migration-v11",title:"Migration to 11.0",description:"Migration to React Native Testing Library version 11 from version 9.x or 10.x should be a relatively easy task due small amount of breaking changes.",source:"@site/docs/MigrationV11.md",sourceDirName:".",slug:"/migration-v11",permalink:"/react-native-testing-library/docs/migration-v11",draft:!1,unlisted:!1,editUrl:"https://github.com/callstack/react-native-testing-library/blob/main/website/docs/MigrationV11.md",tags:[],version:"current",frontMatter:{id:"migration-v11",title:"Migration to 11.0"},sidebar:"docs",previous:{title:"Migration to 12.0",permalink:"/react-native-testing-library/docs/migration-v12"},next:{title:"Migration to 9.0",permalink:"/react-native-testing-library/docs/migration-v9"}},c={},d=[{value:"Update to Jest 28 if you use fake timers",id:"update-to-jest-28-if-you-use-fake-timers",level:3},{value:"Refactor legacy waitForOptions position",id:"refactor-legacy-waitforoptions-position",level:3},{value:"Triggering non-touch events on targets with pointerEvents="box-none" prop",id:"triggering-non-touch-events-on-targets-with-pointereventsbox-none-prop",level:3},{value:"All changes",id:"all-changes",level:2},{value:"Full Changelog",id:"full-changelog",level:2}];function u(e){const t={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",ul:"ul",...(0,a.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(t.p,{children:"Migration to React Native Testing Library version 11 from version 9.x or 10.x should be a relatively easy task due small amount of breaking changes."}),"\n",(0,i.jsx)(r.Z,{toc:d}),"\n",(0,i.jsx)(t.h1,{id:"breaking-changes",children:"Breaking changes"}),"\n",(0,i.jsx)(t.h3,{id:"update-to-jest-28-if-you-use-fake-timers",children:"Update to Jest 28 if you use fake timers"}),"\n",(0,i.jsxs)(t.p,{children:["If you use fake timers in any of your tests you should update your Jest dependencies to version 28. This is due to the fact that ",(0,i.jsxs)(t.a,{href:"https://jestjs.io/docs/jest-object#jestusefaketimersfaketimersconfig",children:[(0,i.jsx)(t.code,{children:"jest.useFakeTimers()"})," config structure"]})," has changed."]}),"\n",(0,i.jsxs)(t.h3,{id:"refactor-legacy-waitforoptions-position",children:["Refactor legacy ",(0,i.jsx)(t.code,{children:"waitForOptions"})," position"]}),"\n",(0,i.jsxs)(t.p,{children:["In version 9 we introducted query ",(0,i.jsx)(t.code,{children:"options"})," parameters for each query type. This affected all ",(0,i.jsx)(t.code,{children:"findBy"})," and ",(0,i.jsx)(t.code,{children:"findAllBy"})," queries because their signatures changed e.g. from:"]}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-ts",children:"function findByText(text: TextMatch, waitForOptions?: WaitForOptions)\nfunction findAllByText(text: TextMatch, waitForOptions?: WaitForOptions)\n"})}),"\n",(0,i.jsx)(t.p,{children:"to"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-ts",children:"function findByText(text: TextMatch, options?: TextMatchOptions, waitForOptions?: WaitForOptions)\nfunction findAllByText(text: TextMatch, options?: TextMatchOptions, waitForOptions?: WaitForOptions)\n"})}),"\n",(0,i.jsxs)(t.p,{children:["In order to facilitate transition, in version 9 and 10, we provided a temporary possibility to pass ",(0,i.jsx)(t.code,{children:"WaitForOptions"})," like ",(0,i.jsx)(t.code,{children:"timeout"}),", ",(0,i.jsx)(t.code,{children:"interval"}),", etc inside ",(0,i.jsx)(t.code,{children:"options"})," argument. From this release we require passing these as the proper third parameter."]}),"\n",(0,i.jsx)(t.p,{children:"This change is easy to implement:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-ts",children:"findByText(/Text/, { timeout: 1000 });\n"})}),"\n",(0,i.jsx)(t.p,{children:"should become"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-ts",children:"findByText(/Text/, {}, { timeout: 1000 });\n"})}),"\n",(0,i.jsxs)(t.h3,{id:"triggering-non-touch-events-on-targets-with-pointereventsbox-none-prop",children:["Triggering non-touch events on targets with ",(0,i.jsx)(t.code,{children:'pointerEvents="box-none"'})," prop"]}),"\n",(0,i.jsxs)(t.p,{children:["Up to version 10, RNTL disables all events for a target with ",(0,i.jsx)(t.code,{children:'pointerEvents="box-none"'}),". This behavior is counter to how React Native itself functions."]}),"\n",(0,i.jsxs)(t.p,{children:["From version 11, RNTL continues to disable ",(0,i.jsx)(t.code,{children:"press"})," event for these targets but allows triggering other events, e.g. ",(0,i.jsx)(t.code,{children:"layout"}),"."]}),"\n",(0,i.jsx)(t.h2,{id:"all-changes",children:"All changes"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsxs)(t.li,{children:["chore(breaking): update Jest to 28 by @mdjastrzebski in ",(0,i.jsx)(t.a,{href:"https://github.com/callstack/react-native-testing-library/pull/1008",children:"https://github.com/callstack/react-native-testing-library/pull/1008"})]}),"\n",(0,i.jsxs)(t.li,{children:["refactor(breaking): remove legacy wait for options support by @mdjastrzebski in ",(0,i.jsx)(t.a,{href:"https://github.com/callstack/react-native-testing-library/pull/1018",children:"https://github.com/callstack/react-native-testing-library/pull/1018"})]}),"\n",(0,i.jsxs)(t.li,{children:["refactor(breaking): remove ",(0,i.jsx)(t.code,{children:"byA11yStates"})," queries by @mdjastrzebski in ",(0,i.jsx)(t.a,{href:"https://github.com/callstack/react-native-testing-library/pull/1015",children:"https://github.com/callstack/react-native-testing-library/pull/1015"})]}),"\n",(0,i.jsxs)(t.li,{children:["chore: update react-native to 0.69.1 by @mdjastrzebski in ",(0,i.jsx)(t.a,{href:"https://github.com/callstack/react-native-testing-library/pull/1010",children:"https://github.com/callstack/react-native-testing-library/pull/1010"})]}),"\n",(0,i.jsxs)(t.li,{children:["chore: update deps @types for react/react-native by @mdjastrzebski in ",(0,i.jsx)(t.a,{href:"https://github.com/callstack/react-native-testing-library/pull/1013",children:"https://github.com/callstack/react-native-testing-library/pull/1013"})]}),"\n",(0,i.jsxs)(t.li,{children:["feat: Trigger non-touch events on box-none targets by @dcalhoun in ",(0,i.jsx)(t.a,{href:"https://github.com/callstack/react-native-testing-library/pull/906",children:"https://github.com/callstack/react-native-testing-library/pull/906"})]}),"\n",(0,i.jsxs)(t.li,{children:["docs: create document describing act function and related errors by @mdjastrzebski in ",(0,i.jsx)(t.a,{href:"https://github.com/callstack/react-native-testing-library/pull/969",children:"https://github.com/callstack/react-native-testing-library/pull/969"})]}),"\n",(0,i.jsxs)(t.li,{children:["chore: Organise a11y queries by predicate by @MattAgn in ",(0,i.jsx)(t.a,{href:"https://github.com/callstack/react-native-testing-library/pull/977",children:"https://github.com/callstack/react-native-testing-library/pull/977"})]}),"\n",(0,i.jsxs)(t.li,{children:["chore: reenable skipped byText tests by @mdjastrzebski in ",(0,i.jsx)(t.a,{href:"https://github.com/callstack/react-native-testing-library/pull/1017",children:"https://github.com/callstack/react-native-testing-library/pull/1017"})]}),"\n"]}),"\n",(0,i.jsx)(t.h2,{id:"full-changelog",children:"Full Changelog"}),"\n",(0,i.jsx)(t.p,{children:(0,i.jsx)(t.a,{href:"https://github.com/callstack/react-native-testing-library/compare/v10.1.1...v11.0.0",children:"https://github.com/callstack/react-native-testing-library/compare/v10.1.1...v11.0.0"})})]})}function h(e={}){const{wrapper:t}={...(0,a.a)(),...e.components};return t?(0,i.jsx)(t,{...e,children:(0,i.jsx)(u,{...e})}):u(e)}},1151:(e,t,n)=>{n.d(t,{Z:()=>l,a:()=>s});var i=n(7294);const a={},r=i.createContext(a);function s(e){const t=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function l(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(a):e.components||a:s(e.components),i.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file +"use strict";(self.webpackChunkreact_native_testing_library_website=self.webpackChunkreact_native_testing_library_website||[]).push([[725],{2063:(e,t,n)=>{n.d(t,{Z:()=>s});n(7294);var i=n(1351);const a={tableOfContentsInline:"tableOfContentsInline_prmo"};var r=n(5893);function s(e){let{toc:t,minHeadingLevel:n,maxHeadingLevel:s}=e;return(0,r.jsx)("div",{className:a.tableOfContentsInline,children:(0,r.jsx)(i.Z,{toc:t,minHeadingLevel:n,maxHeadingLevel:s,className:"table-of-contents",linkClassName:null})})}},1351:(e,t,n)=>{n.d(t,{Z:()=>m});var i=n(7294),a=n(6793);function r(e){const t=e.map((e=>({...e,parentIndex:-1,children:[]}))),n=Array(7).fill(-1);t.forEach(((e,t)=>{const i=n.slice(2,e.level);e.parentIndex=Math.max(...i),n[e.level]=t}));const i=[];return t.forEach((e=>{const{parentIndex:n,...a}=e;n>=0?t[n].children.push(a):i.push(a)})),i}function s(e){let{toc:t,minHeadingLevel:n,maxHeadingLevel:i}=e;return t.flatMap((e=>{const t=s({toc:e.children,minHeadingLevel:n,maxHeadingLevel:i});return function(e){return e.level>=n&&e.level<=i}(e)?[{...e,children:t}]:t}))}function l(e){const t=e.getBoundingClientRect();return t.top===t.bottom?l(e.parentNode):t}function o(e,t){var n;let{anchorTopOffset:i}=t;const a=e.find((e=>l(e).top>=i));if(a){var r;return function(e){return e.top>0&&e.bottom{e.current=t?0:document.querySelector(".navbar").clientHeight}),[t]),e}function d(e){const t=(0,i.useRef)(void 0),n=c();(0,i.useEffect)((()=>{if(!e)return()=>{};const{linkClassName:i,linkActiveClassName:a,minHeadingLevel:r,maxHeadingLevel:s}=e;function l(){const e=function(e){return Array.from(document.getElementsByClassName(e))}(i),l=function(e){let{minHeadingLevel:t,maxHeadingLevel:n}=e;const i=[];for(let a=t;a<=n;a+=1)i.push("h"+a+".anchor");return Array.from(document.querySelectorAll(i.join()))}({minHeadingLevel:r,maxHeadingLevel:s}),c=o(l,{anchorTopOffset:n.current}),d=e.find((e=>c&&c.id===function(e){return decodeURIComponent(e.href.substring(e.href.indexOf("#")+1))}(e)));e.forEach((e=>{!function(e,n){n?(t.current&&t.current!==e&&t.current.classList.remove(a),e.classList.add(a),t.current=e):e.classList.remove(a)}(e,e===d)}))}return document.addEventListener("scroll",l),document.addEventListener("resize",l),l(),()=>{document.removeEventListener("scroll",l),document.removeEventListener("resize",l)}}),[e,n])}var u=n(8746),h=n(5893);function g(e){let{toc:t,className:n,linkClassName:i,isChild:a}=e;return t.length?(0,h.jsx)("ul",{className:a?void 0:n,children:t.map((e=>(0,h.jsxs)("li",{children:[(0,h.jsx)(u.Z,{to:"#"+e.id,className:null!=i?i:void 0,dangerouslySetInnerHTML:{__html:e.value}}),(0,h.jsx)(g,{isChild:!0,toc:e.children,className:n,linkClassName:i})]},e.id)))}):null}const p=i.memo(g);function m(e){let{toc:t,className:n="table-of-contents table-of-contents__left-border",linkClassName:l="table-of-contents__link",linkActiveClassName:o,minHeadingLevel:c,maxHeadingLevel:u,...g}=e;const m=(0,a.L)(),v=null!=c?c:m.tableOfContents.minHeadingLevel,f=null!=u?u:m.tableOfContents.maxHeadingLevel,x=function(e){let{toc:t,minHeadingLevel:n,maxHeadingLevel:a}=e;return(0,i.useMemo)((()=>s({toc:r(t),minHeadingLevel:n,maxHeadingLevel:a})),[t,n,a])}({toc:t,minHeadingLevel:v,maxHeadingLevel:f});return d((0,i.useMemo)((()=>{if(l&&o)return{linkClassName:l,linkActiveClassName:o,minHeadingLevel:v,maxHeadingLevel:f}}),[l,o,v,f])),(0,h.jsx)(p,{toc:x,className:n,linkClassName:l,...g})}},818:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>l,default:()=>h,frontMatter:()=>s,metadata:()=>o,toc:()=>d});var i=n(5893),a=n(1151),r=n(2063);const s={id:"migration-v11",title:"Migration to 11.0"},l="Breaking changes",o={id:"migration-v11",title:"Migration to 11.0",description:"Migration to React Native Testing Library version 11 from version 9.x or 10.x should be a relatively easy task due small amount of breaking changes.",source:"@site/docs/MigrationV11.md",sourceDirName:".",slug:"/migration-v11",permalink:"/react-native-testing-library/docs/migration-v11",draft:!1,unlisted:!1,editUrl:"https://github.com/callstack/react-native-testing-library/blob/main/website/docs/MigrationV11.md",tags:[],version:"current",frontMatter:{id:"migration-v11",title:"Migration to 11.0"},sidebar:"docs",previous:{title:"Migration to 12.0",permalink:"/react-native-testing-library/docs/migration-v12"},next:{title:"Migration to 9.0",permalink:"/react-native-testing-library/docs/migration-v9"}},c={},d=[{value:"Update to Jest 28 if you use fake timers",id:"update-to-jest-28-if-you-use-fake-timers",level:3},{value:"Refactor legacy waitForOptions position",id:"refactor-legacy-waitforoptions-position",level:3},{value:"Triggering non-touch events on targets with pointerEvents="box-none" prop",id:"triggering-non-touch-events-on-targets-with-pointereventsbox-none-prop",level:3},{value:"All changes",id:"all-changes",level:2},{value:"Full Changelog",id:"full-changelog",level:2}];function u(e){const t={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",ul:"ul",...(0,a.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(t.p,{children:"Migration to React Native Testing Library version 11 from version 9.x or 10.x should be a relatively easy task due small amount of breaking changes."}),"\n",(0,i.jsx)(r.Z,{toc:d}),"\n",(0,i.jsx)(t.h1,{id:"breaking-changes",children:"Breaking changes"}),"\n",(0,i.jsx)(t.h3,{id:"update-to-jest-28-if-you-use-fake-timers",children:"Update to Jest 28 if you use fake timers"}),"\n",(0,i.jsxs)(t.p,{children:["If you use fake timers in any of your tests you should update your Jest dependencies to version 28. This is due to the fact that ",(0,i.jsxs)(t.a,{href:"https://jestjs.io/docs/jest-object#jestusefaketimersfaketimersconfig",children:[(0,i.jsx)(t.code,{children:"jest.useFakeTimers()"})," config structure"]})," has changed."]}),"\n",(0,i.jsxs)(t.h3,{id:"refactor-legacy-waitforoptions-position",children:["Refactor legacy ",(0,i.jsx)(t.code,{children:"waitForOptions"})," position"]}),"\n",(0,i.jsxs)(t.p,{children:["In version 9 we introducted query ",(0,i.jsx)(t.code,{children:"options"})," parameters for each query type. This affected all ",(0,i.jsx)(t.code,{children:"findBy"})," and ",(0,i.jsx)(t.code,{children:"findAllBy"})," queries because their signatures changed e.g. from:"]}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-ts",children:"function findByText(text: TextMatch, waitForOptions?: WaitForOptions);\nfunction findAllByText(text: TextMatch, waitForOptions?: WaitForOptions);\n"})}),"\n",(0,i.jsx)(t.p,{children:"to"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-ts",children:"function findByText(text: TextMatch, options?: TextMatchOptions, waitForOptions?: WaitForOptions)\nfunction findAllByText(text: TextMatch, options?: TextMatchOptions, waitForOptions?: WaitForOptions)\n"})}),"\n",(0,i.jsxs)(t.p,{children:["In order to facilitate transition, in version 9 and 10, we provided a temporary possibility to pass ",(0,i.jsx)(t.code,{children:"WaitForOptions"})," like ",(0,i.jsx)(t.code,{children:"timeout"}),", ",(0,i.jsx)(t.code,{children:"interval"}),", etc inside ",(0,i.jsx)(t.code,{children:"options"})," argument. From this release we require passing these as the proper third parameter."]}),"\n",(0,i.jsx)(t.p,{children:"This change is easy to implement:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-ts",children:"findByText(/Text/, { timeout: 1000 });\n"})}),"\n",(0,i.jsx)(t.p,{children:"should become"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-ts",children:"findByText(/Text/, {}, { timeout: 1000 });\n"})}),"\n",(0,i.jsxs)(t.h3,{id:"triggering-non-touch-events-on-targets-with-pointereventsbox-none-prop",children:["Triggering non-touch events on targets with ",(0,i.jsx)(t.code,{children:'pointerEvents="box-none"'})," prop"]}),"\n",(0,i.jsxs)(t.p,{children:["Up to version 10, RNTL disables all events for a target with ",(0,i.jsx)(t.code,{children:'pointerEvents="box-none"'}),". This behavior is counter to how React Native itself functions."]}),"\n",(0,i.jsxs)(t.p,{children:["From version 11, RNTL continues to disable ",(0,i.jsx)(t.code,{children:"press"})," event for these targets but allows triggering other events, e.g. ",(0,i.jsx)(t.code,{children:"layout"}),"."]}),"\n",(0,i.jsx)(t.h2,{id:"all-changes",children:"All changes"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsxs)(t.li,{children:["chore(breaking): update Jest to 28 by @mdjastrzebski in ",(0,i.jsx)(t.a,{href:"https://github.com/callstack/react-native-testing-library/pull/1008",children:"https://github.com/callstack/react-native-testing-library/pull/1008"})]}),"\n",(0,i.jsxs)(t.li,{children:["refactor(breaking): remove legacy wait for options support by @mdjastrzebski in ",(0,i.jsx)(t.a,{href:"https://github.com/callstack/react-native-testing-library/pull/1018",children:"https://github.com/callstack/react-native-testing-library/pull/1018"})]}),"\n",(0,i.jsxs)(t.li,{children:["refactor(breaking): remove ",(0,i.jsx)(t.code,{children:"byA11yStates"})," queries by @mdjastrzebski in ",(0,i.jsx)(t.a,{href:"https://github.com/callstack/react-native-testing-library/pull/1015",children:"https://github.com/callstack/react-native-testing-library/pull/1015"})]}),"\n",(0,i.jsxs)(t.li,{children:["chore: update react-native to 0.69.1 by @mdjastrzebski in ",(0,i.jsx)(t.a,{href:"https://github.com/callstack/react-native-testing-library/pull/1010",children:"https://github.com/callstack/react-native-testing-library/pull/1010"})]}),"\n",(0,i.jsxs)(t.li,{children:["chore: update deps @types for react/react-native by @mdjastrzebski in ",(0,i.jsx)(t.a,{href:"https://github.com/callstack/react-native-testing-library/pull/1013",children:"https://github.com/callstack/react-native-testing-library/pull/1013"})]}),"\n",(0,i.jsxs)(t.li,{children:["feat: Trigger non-touch events on box-none targets by @dcalhoun in ",(0,i.jsx)(t.a,{href:"https://github.com/callstack/react-native-testing-library/pull/906",children:"https://github.com/callstack/react-native-testing-library/pull/906"})]}),"\n",(0,i.jsxs)(t.li,{children:["docs: create document describing act function and related errors by @mdjastrzebski in ",(0,i.jsx)(t.a,{href:"https://github.com/callstack/react-native-testing-library/pull/969",children:"https://github.com/callstack/react-native-testing-library/pull/969"})]}),"\n",(0,i.jsxs)(t.li,{children:["chore: Organise a11y queries by predicate by @MattAgn in ",(0,i.jsx)(t.a,{href:"https://github.com/callstack/react-native-testing-library/pull/977",children:"https://github.com/callstack/react-native-testing-library/pull/977"})]}),"\n",(0,i.jsxs)(t.li,{children:["chore: reenable skipped byText tests by @mdjastrzebski in ",(0,i.jsx)(t.a,{href:"https://github.com/callstack/react-native-testing-library/pull/1017",children:"https://github.com/callstack/react-native-testing-library/pull/1017"})]}),"\n"]}),"\n",(0,i.jsx)(t.h2,{id:"full-changelog",children:"Full Changelog"}),"\n",(0,i.jsx)(t.p,{children:(0,i.jsx)(t.a,{href:"https://github.com/callstack/react-native-testing-library/compare/v10.1.1...v11.0.0",children:"https://github.com/callstack/react-native-testing-library/compare/v10.1.1...v11.0.0"})})]})}function h(e={}){const{wrapper:t}={...(0,a.a)(),...e.components};return t?(0,i.jsx)(t,{...e,children:(0,i.jsx)(u,{...e})}):u(e)}},1151:(e,t,n)=>{n.d(t,{Z:()=>l,a:()=>s});var i=n(7294);const a={},r=i.createContext(a);function s(e){const t=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function l(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(a):e.components||a:s(e.components),i.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/c8229a80.1e5ae667.js b/assets/js/c8229a80.1e5ae667.js new file mode 100644 index 00000000..911b8ed3 --- /dev/null +++ b/assets/js/c8229a80.1e5ae667.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkreact_native_testing_library_website=self.webpackChunkreact_native_testing_library_website||[]).push([[298],{2063:(e,n,t)=>{t.d(n,{Z:()=>o});t(7294);var i=t(1351);const s={tableOfContentsInline:"tableOfContentsInline_prmo"};var r=t(5893);function o(e){let{toc:n,minHeadingLevel:t,maxHeadingLevel:o}=e;return(0,r.jsx)("div",{className:s.tableOfContentsInline,children:(0,r.jsx)(i.Z,{toc:n,minHeadingLevel:t,maxHeadingLevel:o,className:"table-of-contents",linkClassName:null})})}},1351:(e,n,t)=>{t.d(n,{Z:()=>m});var i=t(7294),s=t(6793);function r(e){const n=e.map((e=>({...e,parentIndex:-1,children:[]}))),t=Array(7).fill(-1);n.forEach(((e,n)=>{const i=t.slice(2,e.level);e.parentIndex=Math.max(...i),t[e.level]=n}));const i=[];return n.forEach((e=>{const{parentIndex:t,...s}=e;t>=0?n[t].children.push(s):i.push(s)})),i}function o(e){let{toc:n,minHeadingLevel:t,maxHeadingLevel:i}=e;return n.flatMap((e=>{const n=o({toc:e.children,minHeadingLevel:t,maxHeadingLevel:i});return function(e){return e.level>=t&&e.level<=i}(e)?[{...e,children:n}]:n}))}function c(e){const n=e.getBoundingClientRect();return n.top===n.bottom?c(e.parentNode):n}function l(e,n){var t;let{anchorTopOffset:i}=n;const s=e.find((e=>c(e).top>=i));if(s){var r;return function(e){return e.top>0&&e.bottom{e.current=n?0:document.querySelector(".navbar").clientHeight}),[n]),e}function d(e){const n=(0,i.useRef)(void 0),t=a();(0,i.useEffect)((()=>{if(!e)return()=>{};const{linkClassName:i,linkActiveClassName:s,minHeadingLevel:r,maxHeadingLevel:o}=e;function c(){const e=function(e){return Array.from(document.getElementsByClassName(e))}(i),c=function(e){let{minHeadingLevel:n,maxHeadingLevel:t}=e;const i=[];for(let s=n;s<=t;s+=1)i.push("h"+s+".anchor");return Array.from(document.querySelectorAll(i.join()))}({minHeadingLevel:r,maxHeadingLevel:o}),a=l(c,{anchorTopOffset:t.current}),d=e.find((e=>a&&a.id===function(e){return decodeURIComponent(e.href.substring(e.href.indexOf("#")+1))}(e)));e.forEach((e=>{!function(e,t){t?(n.current&&n.current!==e&&n.current.classList.remove(s),e.classList.add(s),n.current=e):e.classList.remove(s)}(e,e===d)}))}return document.addEventListener("scroll",c),document.addEventListener("resize",c),c(),()=>{document.removeEventListener("scroll",c),document.removeEventListener("resize",c)}}),[e,t])}var h=t(8746),u=t(5893);function p(e){let{toc:n,className:t,linkClassName:i,isChild:s}=e;return n.length?(0,u.jsx)("ul",{className:s?void 0:t,children:n.map((e=>(0,u.jsxs)("li",{children:[(0,u.jsx)(h.Z,{to:"#"+e.id,className:null!=i?i:void 0,dangerouslySetInnerHTML:{__html:e.value}}),(0,u.jsx)(p,{isChild:!0,toc:e.children,className:t,linkClassName:i})]},e.id)))}):null}const x=i.memo(p);function m(e){let{toc:n,className:t="table-of-contents table-of-contents__left-border",linkClassName:c="table-of-contents__link",linkActiveClassName:l,minHeadingLevel:a,maxHeadingLevel:h,...p}=e;const m=(0,s.L)(),j=null!=a?a:m.tableOfContents.minHeadingLevel,f=null!=h?h:m.tableOfContents.maxHeadingLevel,g=function(e){let{toc:n,minHeadingLevel:t,maxHeadingLevel:s}=e;return(0,i.useMemo)((()=>o({toc:r(n),minHeadingLevel:t,maxHeadingLevel:s})),[n,t,s])}({toc:n,minHeadingLevel:j,maxHeadingLevel:f});return d((0,i.useMemo)((()=>{if(c&&l)return{linkClassName:c,linkActiveClassName:l,minHeadingLevel:j,maxHeadingLevel:f}}),[c,l,j,f])),(0,u.jsx)(x,{toc:g,className:t,linkClassName:c,...p})}},1804:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>a,contentTitle:()=>c,default:()=>u,frontMatter:()=>o,metadata:()=>l,toc:()=>d});var i=t(5893),s=t(1151),r=t(2063);const o={id:"api",title:"API"},c=void 0,l={id:"api",title:"API",description:"render API",source:"@site/docs/API.md",sourceDirName:".",slug:"/api",permalink:"/react-native-testing-library/docs/api",draft:!1,unlisted:!1,editUrl:"https://github.com/callstack/react-native-testing-library/blob/main/website/docs/API.md",tags:[],version:"current",frontMatter:{id:"api",title:"API"},sidebar:"docs",previous:{title:"Getting Started",permalink:"/react-native-testing-library/docs/getting-started"},next:{title:"Queries",permalink:"/react-native-testing-library/docs/api-queries"}},a={},d=[{value:"render API",id:"render-api",level:2},{value:"Options",id:"render-options",level:3},{value:"wrapper option",id:"wrapper-option",level:4},{value:"createNodeMock option",id:"createnodemock-option",level:4},{value:"unstable_validateStringsRenderedWithinText option",id:"unstable_validatestringsrenderedwithintext-option",level:4},{value:"...queries",id:"queries",level:3},{value:"Example",id:"example",level:4},{value:"update",id:"update",level:3},{value:"unmount",id:"unmount",level:3},{value:"debug",id:"debug",level:3},{value:"message option",id:"message-option",level:4},{value:"mapProps option",id:"mapprops-option",level:4},{value:"debug.shallow",id:"debugshallow",level:4},{value:"toJSON",id:"tojson",level:3},{value:"root",id:"root",level:3},{value:"UNSAFE_root",id:"unsafe_root",level:3},{value:"screen API",id:"screen-api",level:2},{value:"fireEvent API",id:"fireevent-api",level:2},{value:"fireEvent.press",id:"fireeventpress",level:3},{value:"fireEvent.changeText",id:"fireeventchangetext",level:3},{value:"fireEvent.scroll",id:"fireeventscroll",level:3},{value:"On a ScrollView",id:"on-a-scrollview",level:4},{value:"Helper functions",id:"helper-functions",level:2},{value:"waitFor",id:"waitfor",level:3},{value:"Using a React Native version < 0.71 with Jest fake timers",id:"using-a-react-native-version--071-with-jest-fake-timers",level:4},{value:"waitForElementToBeRemoved",id:"waitforelementtoberemoved",level:3},{value:"within, getQueriesForElement",id:"within-getqueriesforelement",level:3},{value:"act",id:"act",level:3},{value:"cleanup",id:"cleanup",level:3},{value:"renderHook API",id:"renderhook-api",level:2},{value:"options",id:"options",level:3},{value:"initialProps",id:"initialprops",level:4},{value:"wrapper",id:"wrapper",level:4},{value:"RenderHookResult",id:"renderhookresult",level:3},{value:"result",id:"result",level:3},{value:"rerender",id:"rerender",level:3},{value:"unmount",id:"unmount-1",level:3},{value:"Examples",id:"examples",level:3},{value:"With initialProps",id:"with-initialprops",level:4},{value:"With wrapper",id:"with-wrapper",level:4},{value:"Configuration",id:"configuration",level:2},{value:"configure",id:"configure",level:3},{value:"asyncUtilTimeout option",id:"asyncutiltimeout-option",level:4},{value:"defaultIncludeHiddenElements option",id:"defaultincludehiddenelements-option",level:4},{value:"defaultDebugOptions option",id:"defaultdebugoptions-option",level:4},{value:"resetToDefaults()",id:"resettodefaults",level:3},{value:"Environment variables",id:"environment-variables",level:3},{value:"RNTL_SKIP_AUTO_CLEANUP",id:"rntl_skip_auto_cleanup",level:4},{value:"RNTL_SKIP_AUTO_DETECT_FAKE_TIMERS",id:"rntl_skip_auto_detect_fake_timers",level:4},{value:"Accessibility",id:"accessibility",level:2},{value:"isHiddenFromAccessibility",id:"ishiddenfromaccessibility",level:3}];function h(e){const n={a:"a",admonition:"admonition",blockquote:"blockquote",code:"code",em:"em",h2:"h2",h3:"h3",h4:"h4",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(r.Z,{toc:d}),"\n",(0,i.jsxs)(n.h2,{id:"render-api",children:[(0,i.jsx)(n.code,{children:"render"})," API"]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"https://github.com/callstack/react-native-testing-library/blob/main/src/__tests__/render.test.tsx",children:(0,i.jsx)(n.code,{children:"Example code"})})}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"Defined as:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-jsx",children:"function render(\n component: React.Element,\n options?: RenderOptions\n): RenderResult {}\n"})}),"\n",(0,i.jsx)(n.p,{children:"Deeply renders given React element and returns helpers to query the output components structure."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-jsx",children:"import { render } from '@testing-library/react-native';\nimport { QuestionsBoard } from '../QuestionsBoard';\n\ntest('should verify two questions', () => {\n render();\n const allQuestions = screen.queryAllByRole('header');\n\n expect(allQuestions).toHaveLength(2);\n});\n"})}),"\n",(0,i.jsxs)(n.blockquote,{children:["\n",(0,i.jsxs)(n.p,{children:["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 ",(0,i.jsx)(n.code,{children:"render"})," method. ",(0,i.jsx)(n.a,{href:"https://testing-library.com/docs/react-testing-library/setup#custom-render",children:"Follow this great guide on how to set this up"}),"."]}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"render"})," method returns a ",(0,i.jsx)(n.code,{children:"RenderResult"})," object having properties described below."]}),"\n",(0,i.jsxs)(n.admonition,{type:"info",children:[(0,i.jsxs)(n.p,{children:["Latest ",(0,i.jsx)(n.code,{children:"render"})," result is kept in ",(0,i.jsx)(n.a,{href:"#screen",children:(0,i.jsx)(n.code,{children:"screen"})})," variable that can be imported from ",(0,i.jsx)(n.code,{children:"@testing-library/react-native"})," package."]}),(0,i.jsxs)(n.p,{children:["Using ",(0,i.jsx)(n.code,{children:"screen"})," instead of destructuring ",(0,i.jsx)(n.code,{children:"render"})," result is recommended approach. See ",(0,i.jsx)(n.a,{href:"https://kentcdodds.com/blog/common-mistakes-with-react-testing-library#not-using-screen",children:"this article"})," from Kent C. Dodds for more details."]})]}),"\n",(0,i.jsx)(n.h3,{id:"render-options",children:"Options"}),"\n",(0,i.jsxs)(n.p,{children:["The behavior of ",(0,i.jsx)(n.code,{children:"render"})," method can be customized by passing various options as a second argument of ",(0,i.jsx)(n.code,{children:"RenderOptions"})," type:"]}),"\n",(0,i.jsxs)(n.h4,{id:"wrapper-option",children:[(0,i.jsx)(n.code,{children:"wrapper"})," option"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"wrapper?: React.ComponentType,\n"})}),"\n",(0,i.jsxs)(n.p,{children:["This options allows you to wrap tested component, passed as the first option to the ",(0,i.jsx)(n.code,{children:"render()"})," function, in additional wrapper component. This is most useful for creating reusable custom render functions for common React Context providers."]}),"\n",(0,i.jsxs)(n.h4,{id:"createnodemock-option",children:[(0,i.jsx)(n.code,{children:"createNodeMock"})," option"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"createNodeMock?: (element: React.Element) => any,\n"})}),"\n",(0,i.jsxs)(n.p,{children:["This options allows you to pass ",(0,i.jsx)(n.code,{children:"createNodeMock"})," option to ",(0,i.jsx)(n.code,{children:"ReactTestRenderer.create()"})," method in order to allow for custom mock refs. You can learn more about this options from ",(0,i.jsx)(n.a,{href:"https://reactjs.org/docs/test-renderer.html#ideas",children:"React Test Renderer documentation"}),"."]}),"\n",(0,i.jsxs)(n.h4,{id:"unstable_validatestringsrenderedwithintext-option",children:[(0,i.jsx)(n.code,{children:"unstable_validateStringsRenderedWithinText"})," option"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"unstable_validateStringsRenderedWithinText?: boolean;\n"})}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsxs)(n.p,{children:["This options is experimental, in some cases it might not work as intended, and its behavior might change without observing ",(0,i.jsx)(n.a,{href:"https://semver.org/",children:"SemVer"})," requirements for breaking changes."]})}),"\n",(0,i.jsxs)(n.p,{children:["This ",(0,i.jsx)(n.strong,{children:"experimental"})," option allows you to replicate React Native behavior of throwing ",(0,i.jsx)(n.code,{children:"Invariant Violation: Text strings must be rendered within a component"})," error when you try to render ",(0,i.jsx)(n.code,{children:"string"})," value under components different than ",(0,i.jsx)(n.code,{children:""}),", e.g. under ",(0,i.jsx)(n.code,{children:""}),"."]}),"\n",(0,i.jsx)(n.p,{children:"This check is not enforced by React Test Renderer and hence by default React Native Testing Library also does not check this. That might result in runtime errors when running your code on a device, while the code works without errors in tests."}),"\n",(0,i.jsx)(n.h3,{id:"queries",children:(0,i.jsx)(n.code,{children:"...queries"})}),"\n",(0,i.jsxs)(n.p,{children:["The most important feature of ",(0,i.jsx)(n.code,{children:"render"})," is providing a set of helpful queries that allow you to find certain elements in the view hierarchy."]}),"\n",(0,i.jsxs)(n.p,{children:["See ",(0,i.jsx)(n.a,{href:"/react-native-testing-library/docs/api-queries",children:"Queries"})," for a complete list."]}),"\n",(0,i.jsx)(n.h4,{id:"example",children:"Example"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-jsx",children:"import { render } from '@testing-library/react-native';\n\nconst { getByText, queryByA11yState } = render();\n"})}),"\n",(0,i.jsx)(n.h3,{id:"update",children:(0,i.jsx)(n.code,{children:"update"})}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsxs)(n.em,{children:["Also available under ",(0,i.jsx)(n.code,{children:"rerender"})," alias"]})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"update(element: React.Element): void\nrerender(element: React.Element): void\n"})}),"\n",(0,i.jsxs)(n.p,{children:["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 ",(0,i.jsx)(n.code,{children:"componentDidUpdate"})," behavior, by passing updated props to the component."]}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.a,{href:"https://github.com/callstack/react-native-testing-library/blob/f96d782d26dd4815dbfd01de6ef7a647efd1f693/src/__tests__/act.test.js#L31-L37",children:"Example code"})}),"\n",(0,i.jsx)(n.h3,{id:"unmount",children:(0,i.jsx)(n.code,{children:"unmount"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"unmount(): void\n"})}),"\n",(0,i.jsx)(n.p,{children:"Unmount the in-memory tree, triggering the appropriate lifecycle events."}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsxs)(n.p,{children:["Usually you should not need to call ",(0,i.jsx)(n.code,{children:"unmount"})," as it is done automatically if your test runner supports ",(0,i.jsx)(n.code,{children:"afterEach"})," hook (like Jest, mocha, Jasmine)."]})}),"\n",(0,i.jsx)(n.h3,{id:"debug",children:(0,i.jsx)(n.code,{children:"debug"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"interface DebugOptions {\n message?: string;\n mapProps?: MapPropsFunction;\n}\n\ndebug(options?: DebugOptions | string): void\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Pretty prints deeply rendered component passed to ",(0,i.jsx)(n.code,{children:"render"}),"."]}),"\n",(0,i.jsxs)(n.h4,{id:"message-option",children:[(0,i.jsx)(n.code,{children:"message"})," option"]}),"\n",(0,i.jsx)(n.p,{children:"You can provide a message that will be printed on top."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-jsx",children:"render();\nscreen.debug({ message: 'optional message' });\n"})}),"\n",(0,i.jsx)(n.p,{children:"logs optional message and colored JSX:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-jsx",children:"optional message\n\n\n Press me\n\n"})}),"\n",(0,i.jsxs)(n.h4,{id:"mapprops-option",children:[(0,i.jsx)(n.code,{children:"mapProps"})," option"]}),"\n",(0,i.jsxs)(n.p,{children:["You can use the ",(0,i.jsx)(n.code,{children:"mapProps"})," option to transform the props that will be printed :"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-jsx",children:"render();\ndebug({ mapProps: ({ style, ...props }) => ({ props }) });\n"})}),"\n",(0,i.jsxs)(n.p,{children:["This will log the rendered JSX without the ",(0,i.jsx)(n.code,{children:"style"})," props."]}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"children"})," prop cannot be filtered out so the following will print all rendered components with all props but ",(0,i.jsx)(n.code,{children:"children"})," filtered out."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"debug({ mapProps: (props) => ({}) });\n"})}),"\n",(0,i.jsxs)(n.p,{children:["This option can be used to target specific props when debugging a query (for instance keeping only ",(0,i.jsx)(n.code,{children:"children"})," prop when debugging a ",(0,i.jsx)(n.code,{children:"getByText"})," query)."]}),"\n",(0,i.jsx)(n.p,{children:"You can also transform prop values so that they are more readable (e.g. flatten styles)."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"import { StyleSheet } from 'react-native';\n\ndebug({ mapProps : {({ style, ...props })} => ({ style : StyleSheet.flatten(style), ...props }) });\n"})}),"\n",(0,i.jsx)(n.p,{children:"Or remove props that have little value when debugging tests, e.g. path prop for svgs"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"debug({ mapProps: ({ path, ...props }) => ({ ...props }) });\n"})}),"\n",(0,i.jsx)(n.h4,{id:"debugshallow",children:(0,i.jsx)(n.code,{children:"debug.shallow"})}),"\n",(0,i.jsxs)(n.p,{children:["Pretty prints shallowly rendered component passed to ",(0,i.jsx)(n.code,{children:"render"})," with optional message on top."]}),"\n",(0,i.jsx)(n.h3,{id:"tojson",children:(0,i.jsx)(n.code,{children:"toJSON"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"toJSON(): ReactTestRendererJSON | null\n"})}),"\n",(0,i.jsx)(n.p,{children:"Get the rendered component JSON representation, e.g. for snapshot testing."}),"\n",(0,i.jsx)(n.h3,{id:"root",children:(0,i.jsx)(n.code,{children:"root"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"root: ReactTestInstance;\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Returns the rendered root ",(0,i.jsx)(n.a,{href:"testing-env#host-and-composite-components",children:"host element"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["This API is primarily useful in component tests, as it allows you to access root host view without using ",(0,i.jsx)(n.code,{children:"*ByTestId"})," queries or similar methods."]}),"\n",(0,i.jsx)(n.h3,{id:"unsafe_root",children:(0,i.jsx)(n.code,{children:"UNSAFE_root"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"UNSAFE_root: ReactTestInstance;\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Returns the rendered ",(0,i.jsx)(n.a,{href:"testing-env#host-and-composite-components",children:"composite root element"}),"."]}),"\n",(0,i.jsx)(n.admonition,{type:"caution",children:(0,i.jsx)(n.p,{children:"This API typically will return a composite view which goes against recommended testing practices. This API is primarily available for legacy test suites that rely on such testing."})}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsxs)(n.p,{children:["This API has been previously named ",(0,i.jsx)(n.code,{children:"container"})," for compatibility with ",(0,i.jsx)(n.a,{href:"https://testing-library.com/docs/react-testing-library/api#container-1",children:"React Testing Library"}),". However, despite the same name, the actual behavior has been signficantly different, hence the name change to ",(0,i.jsx)(n.code,{children:"UNSAFE_root"}),"."]})}),"\n",(0,i.jsxs)(n.h2,{id:"screen-api",children:[(0,i.jsx)(n.code,{children:"screen"})," API"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"let screen: RenderResult;\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Hold the value of latest render call for easier access to query and other functions returned by ",(0,i.jsx)(n.a,{href:"#render",children:(0,i.jsx)(n.code,{children:"render"})}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["Its value is automatically cleared after each test by calling ",(0,i.jsx)(n.a,{href:"#cleanup",children:(0,i.jsx)(n.code,{children:"cleanup"})}),". If no ",(0,i.jsx)(n.code,{children:"render"})," call has been made in a given test then it holds a special object that implements ",(0,i.jsx)(n.code,{children:"RenderResult"})," but throws a helpful error on each property and method access."]}),"\n",(0,i.jsx)(n.p,{children:"This can also be used to build test utils that would normally require to be in render scope, either in a test file or globally for your project. For instance:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"// Prints the rendered components omitting all props except children.\nconst debugText = () => screen.debug({ mapProps: (props) => ({}) });\n"})}),"\n",(0,i.jsxs)(n.h2,{id:"fireevent-api",children:[(0,i.jsx)(n.code,{children:"fireEvent"})," API"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"function fireEvent(\n element: ReactTestInstance,\n eventName: string,\n ...data: Array\n): void {}\n"})}),"\n",(0,i.jsxs)(n.admonition,{type:"note",children:[(0,i.jsxs)(n.p,{children:["For common events like ",(0,i.jsx)(n.code,{children:"press"})," or ",(0,i.jsx)(n.code,{children:"type"})," it's recommended to use ",(0,i.jsx)(n.a,{href:"/react-native-testing-library/docs/user-event",children:"User Event API"})," as it offers\nmore realistic event simulation by emitting a sequence of events with proper event objects that mimic React Native runtime behavior."]}),(0,i.jsx)(n.p,{children:"Use Fire Event for cases not supported by User Event and for triggering event handlers on composite components."})]}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.code,{children:"fireEvent"})," API allows you to trigger all kind of event handlers on both host and composite components. It will try to invoke a single event handler traversing the component tree bottom-up from passed element and trying to find enabled event handler named ",(0,i.jsx)(n.code,{children:"onXxx"})," when ",(0,i.jsx)(n.code,{children:"xxx"})," is the name of the event passed."]}),"\n",(0,i.jsx)(n.p,{children:"Unlike User Event, this API does not automatically pass event object to event handler, this is responsibility of the user to construct such object."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-jsx",children:"import { render, screen, fireEvent } from '@testing-library/react-native';\n\ntest('fire changeText event', () => {\n const onEventMock = jest.fn();\n render(\n // MyComponent renders TextInput which has a placeholder 'Enter details'\n // and with `onChangeText` bound to handleChangeText\n ,\n );\n\n fireEvent(screen.getByPlaceholderText('change'), 'onChangeText', 'ab');\n expect(onEventMock).toHaveBeenCalledWith('ab');\n});\n"})}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsxs)(n.p,{children:["Please note that from version ",(0,i.jsx)(n.code,{children:"7.0"})," ",(0,i.jsx)(n.code,{children:"fireEvent"})," performs checks that should prevent events firing on disabled elements."]})}),"\n",(0,i.jsxs)(n.p,{children:["An example using ",(0,i.jsx)(n.code,{children:"fireEvent"})," with native events that aren't already aliased by the ",(0,i.jsx)(n.code,{children:"fireEvent"})," api."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-jsx",children:"import { TextInput, View } from 'react-native';\nimport { fireEvent, render } from '@testing-library/react-native';\n\nconst onBlurMock = jest.fn();\n\nrender(\n \n \n ,\n);\n\n// you can omit the `on` prefix\nfireEvent(screen.getByPlaceholderText('my placeholder'), 'blur');\n"})}),"\n",(0,i.jsxs)(n.p,{children:["FireEvent exposes convenience methods for common events like: ",(0,i.jsx)(n.code,{children:"press"}),", ",(0,i.jsx)(n.code,{children:"changeText"}),", ",(0,i.jsx)(n.code,{children:"scroll"}),"."]}),"\n",(0,i.jsx)(n.h3,{id:"fireeventpress",children:(0,i.jsx)(n.code,{children:"fireEvent.press"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:"fireEvent.press: (element: ReactTestInstance, ...data: Array) => void\n"})}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsxs)(n.p,{children:["It is recommended to use the User Event ",(0,i.jsx)(n.a,{href:"/react-native-testing-library/docs/user-event#press",children:(0,i.jsx)(n.code,{children:"press()"})})," helper instead as it offers more realistic simulation of press interaction, including pressable support."]})}),"\n",(0,i.jsxs)(n.p,{children:["Invokes ",(0,i.jsx)(n.code,{children:"press"})," event handler on the element or parent element in the tree."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-jsx",children:"import { View, Text, TouchableOpacity } from 'react-native';\nimport { render, screen, fireEvent } from '@testing-library/react-native';\n\nconst onPressMock = jest.fn();\nconst eventData = {\n nativeEvent: {\n pageX: 20,\n pageY: 30,\n },\n};\n\nrender(\n \n \n Press me\n \n ,\n);\n\nfireEvent.press(screen.getByText('Press me'), eventData);\nexpect(onPressMock).toHaveBeenCalledWith(eventData);\n"})}),"\n",(0,i.jsx)(n.h3,{id:"fireeventchangetext",children:(0,i.jsx)(n.code,{children:"fireEvent.changeText"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:"fireEvent.changeText: (element: ReactTestInstance, ...data: Array) => void\n"})}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsxs)(n.p,{children:["It is recommended to use the User Event ",(0,i.jsx)(n.a,{href:"/react-native-testing-library/docs/user-event#type",children:(0,i.jsx)(n.code,{children:"type()"})})," helper instead as it offers more realistic simulation of text change interaction, including key-by-key typing, element focus, and other editing events."]})}),"\n",(0,i.jsxs)(n.p,{children:["Invokes ",(0,i.jsx)(n.code,{children:"changeText"})," event handler on the element or parent element in the tree."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-jsx",children:"import { View, TextInput } from 'react-native';\nimport { render, screen, fireEvent } from '@testing-library/react-native';\n\nconst onChangeTextMock = jest.fn();\nconst CHANGE_TEXT = 'content';\n\nrender(\n \n \n ,\n);\n\nfireEvent.changeText(screen.getByPlaceholderText('Enter data'), CHANGE_TEXT);\n"})}),"\n",(0,i.jsx)(n.h3,{id:"fireeventscroll",children:(0,i.jsx)(n.code,{children:"fireEvent.scroll"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:"fireEvent.scroll: (element: ReactTestInstance, ...data: Array) => void\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Invokes ",(0,i.jsx)(n.code,{children:"scroll"})," event handler on the element or parent element in the tree."]}),"\n",(0,i.jsxs)(n.h4,{id:"on-a-scrollview",children:["On a ",(0,i.jsx)(n.code,{children:"ScrollView"})]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-jsx",children:"import { ScrollView, Text } from 'react-native';\nimport { render, screen, fireEvent } from '@testing-library/react-native';\n\nconst onScrollMock = jest.fn();\nconst eventData = {\n nativeEvent: {\n contentOffset: {\n y: 200,\n },\n },\n};\n\nrender(\n \n XD\n ,\n);\n\nfireEvent.scroll(screen.getByText('scroll-view'), eventData);\n"})}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsxs)(n.p,{children:["Prefer using ",(0,i.jsx)(n.a,{href:"/react-native-testing-library/docs/user-event#scrollto",children:(0,i.jsx)(n.code,{children:"user.scrollTo"})})," over ",(0,i.jsx)(n.code,{children:"fireEvent.scroll"})," for ",(0,i.jsx)(n.code,{children:"ScrollView"}),", ",(0,i.jsx)(n.code,{children:"FlatList"}),", and ",(0,i.jsx)(n.code,{children:"SectionList"})," components. User Event provides a more realistic event simulation based on React Native runtime behavior."]})}),"\n",(0,i.jsx)(n.h2,{id:"helper-functions",children:"Helper functions"}),"\n",(0,i.jsx)(n.h3,{id:"waitfor",children:(0,i.jsx)(n.code,{children:"waitFor"})}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"https://github.com/callstack/react-native-testing-library/blob/main/src/__tests__/wait-for.test.tsx",children:(0,i.jsx)(n.code,{children:"Example code"})})}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"Defined as:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-jsx",children:"function waitFor(\n expectation: () => T,\n { timeout: number = 1000, interval: number = 50 },\n): Promise {}\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Waits for a period of time for the ",(0,i.jsx)(n.code,{children:"expectation"})," callback to pass. ",(0,i.jsx)(n.code,{children:"waitFor"})," may run the callback a number of times until timeout is reached, as specified by the ",(0,i.jsx)(n.code,{children:"timeout"})," and ",(0,i.jsx)(n.code,{children:"interval"})," options. The callback must throw an error when the expectation is not met. Returning any value, including a falsy one, will be treated as meeting the expectation, and the callback result will be returned to the caller of ",(0,i.jsx)(n.code,{children:"waitFor"})," function."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-tsx",children:"await waitFor(() => expect(mockFunction).toHaveBeenCalledWith());\n"})}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.code,{children:"waitFor"})," function will be executing ",(0,i.jsx)(n.code,{children:"expectation"})," callback every ",(0,i.jsx)(n.code,{children:"interval"})," (default: every 50 ms) until ",(0,i.jsx)(n.code,{children:"timeout"})," (default: 1000 ms) is reached. The repeated execution of callback is stopped as soon as it does not throw an error, in such case the value returned by the callback is returned to ",(0,i.jsx)(n.code,{children:"waitFor"})," caller. Otherwise, when it reaches the timeout, the final error thrown by ",(0,i.jsx)(n.code,{children:"expectation"})," will be re-thrown by ",(0,i.jsx)(n.code,{children:"waitFor"})," to the calling code."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-tsx",children:"// \u274c `waitFor` will return immediately because callback does not throw\nawait waitFor(() => false);\n"})}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.code,{children:"waitFor"})," is an async function so you need to ",(0,i.jsx)(n.code,{children:"await"})," the result to pause test execution."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-jsx",children:"// \u274c missing `await`: `waitFor` will just return Promise that will be rejected when the timeout is reached\nwaitFor(() => expect(1).toBe(2));\n"})}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsxs)(n.p,{children:["You can enforce awaiting ",(0,i.jsx)(n.code,{children:"waitFor"})," by using the ",(0,i.jsx)(n.a,{href:"https://github.com/testing-library/eslint-plugin-testing-library/blob/main/docs/rules/await-async-utils.md",children:"await-async-utils"})," rule from ",(0,i.jsx)(n.a,{href:"https://github.com/testing-library/eslint-plugin-testing-library",children:"eslint-plugin-testing-library"}),"."]})}),"\n",(0,i.jsxs)(n.p,{children:["Since ",(0,i.jsx)(n.code,{children:"waitFor"})," is likely to run ",(0,i.jsx)(n.code,{children:"expectation"})," callback multiple times, it is highly recommended for it ",(0,i.jsx)(n.a,{href:"https://kentcdodds.com/blog/common-mistakes-with-react-testing-library#performing-side-effects-in-waitfor",children:"not to perform any side effects"})," in ",(0,i.jsx)(n.code,{children:"waitFor"}),"."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-jsx",children:"await waitFor(() => {\n // \u274c button will be pressed on each waitFor iteration\n fireEvent.press(screen.getByText('press me'));\n expect(mockOnPress).toHaveBeenCalled();\n});\n"})}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsxs)(n.p,{children:["Avoiding side effects in ",(0,i.jsx)(n.code,{children:"expectation"})," callback can be partially enforced with the ",(0,i.jsxs)(n.a,{href:"https://github.com/testing-library/eslint-plugin-testing-library/blob/main/docs/rules/no-wait-for-side-effects.md",children:[(0,i.jsx)(n.code,{children:"no-wait-for-side-effects"})," rule"]}),"."]})}),"\n",(0,i.jsxs)(n.p,{children:["It is also recommended to have a ",(0,i.jsxs)(n.a,{href:"https://kentcdodds.com/blog/common-mistakes-with-react-testing-library#having-multiple-assertions-in-a-single-waitfor-callback",children:["single assertion per each ",(0,i.jsx)(n.code,{children:"waitFor"})]})," for more consistency and faster failing tests. If you want to make several assertions, then they should be in seperate ",(0,i.jsx)(n.code,{children:"waitFor"})," calls. In many cases you won't actually need to wrap the second assertion in ",(0,i.jsx)(n.code,{children:"waitFor"})," since the first one will do the waiting required for asynchronous change to happen."]}),"\n",(0,i.jsx)(n.h4,{id:"using-a-react-native-version--071-with-jest-fake-timers",children:"Using a React Native version < 0.71 with Jest fake timers"}),"\n",(0,i.jsx)(n.admonition,{type:"caution",children:(0,i.jsxs)(n.p,{children:["When using a version of React Native < 0.71 and modern fake timers (the default for ",(0,i.jsx)(n.code,{children:"Jest"})," >= 27), ",(0,i.jsx)(n.code,{children:"waitFor"})," won't work (it will always timeout even if ",(0,i.jsx)(n.code,{children:"expectation()"})," doesn't throw) unless you use the custom ",(0,i.jsx)(n.a,{href:"https://github.com/callstack/react-native-testing-library#custom-jest-preset",children:"@testing-library/react-native preset"}),"."]})}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.code,{children:"waitFor"})," checks whether Jest fake timers are enabled and adapts its behavior in such case. The following snippet is a simplified version of how it behaves when fake timers are enabled:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-tsx",children:"let fakeTimeRemaining = timeout;\nlet lastError;\n\nwhile (fakeTimeRemaining > 0) {\n fakeTimeRemaining = fakeTimeRemaining - interval;\n jest.advanceTimersByTime(interval);\n try {\n // resolve\n return expectation();\n } catch (error) {\n lastError = error;\n }\n}\n\n// reject\nthrow lastError;\n"})}),"\n",(0,i.jsxs)(n.p,{children:["In the following example we test that a function is called after 10 seconds using fake timers. Since we're using fake timers, the test won't depend on real time passing and thus be much faster and more reliable. Also we don't have to advance fake timers through Jest fake timers API because ",(0,i.jsx)(n.code,{children:"waitFor"})," already does this for us."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-tsx",children:"// in component\nsetTimeout(() => {\n someFunction();\n}, 10000);\n\n// in test\njest.useFakeTimers();\n\nawait waitFor(() => {\n expect(someFunction).toHaveBeenCalledWith();\n}, 10000);\n"})}),"\n",(0,i.jsx)(n.admonition,{type:"info",children:(0,i.jsxs)(n.p,{children:["In order to properly use ",(0,i.jsx)(n.code,{children:"waitFor"})," you need at least React >=16.9.0 (featuring async ",(0,i.jsx)(n.code,{children:"act"}),") or React Native >=0.61 (which comes with React >=16.9.0)."]})}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsxs)(n.p,{children:["If you receive warnings related to ",(0,i.jsx)(n.code,{children:"act()"})," function consult our ",(0,i.jsx)(n.a,{href:"/react-native-testing-library/docs/understanding-act",children:"Undestanding Act"})," function document."]})}),"\n",(0,i.jsx)(n.h3,{id:"waitforelementtoberemoved",children:(0,i.jsx)(n.code,{children:"waitForElementToBeRemoved"})}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["[",(0,i.jsx)(n.code,{children:"Example code"}),"]",(0,i.jsx)(n.a,{href:"https://github.com/callstack/react-native-testing-library/blob/main/src/__tests__/wait-for-element-to-be-removed.test.tsx",children:"https://github.com/callstack/react-native-testing-library/blob/main/src/__tests__/wait-for-element-to-be-removed.test.tsx"}),")"]}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"Defined as:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"function waitForElementToBeRemoved(\n expectation: () => T,\n { timeout: number = 4500, interval: number = 50 },\n): Promise {}\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Waits for non-deterministic periods of time until queried element is removed or times out. ",(0,i.jsx)(n.code,{children:"waitForElementToBeRemoved"})," periodically calls ",(0,i.jsx)(n.code,{children:"expectation"})," every ",(0,i.jsx)(n.code,{children:"interval"})," milliseconds to determine whether the element has been removed or not."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-jsx",children:"import { render, screen, waitForElementToBeRemoved } from '@testing-library/react-native';\n\ntest('waiting for an Banana to be removed', async () => {\n render();\n\n await waitForElementToBeRemoved(() => screen.getByText('Banana ready'));\n});\n"})}),"\n",(0,i.jsx)(n.p,{children:"This method expects that the element is initially 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."}),"\n",(0,i.jsxs)(n.p,{children:["You can use any of ",(0,i.jsx)(n.code,{children:"getBy"}),", ",(0,i.jsx)(n.code,{children:"getAllBy"}),", ",(0,i.jsx)(n.code,{children:"queryBy"})," and ",(0,i.jsx)(n.code,{children:"queryAllBy"})," queries for ",(0,i.jsx)(n.code,{children:"expectation"})," parameter."]}),"\n",(0,i.jsx)(n.admonition,{type:"info",children:(0,i.jsxs)(n.p,{children:["In order to properly use ",(0,i.jsx)(n.code,{children:"waitForElementToBeRemoved"})," you need at least React >=16.9.0 (featuring async ",(0,i.jsx)(n.code,{children:"act"}),") or React Native >=0.61 (which comes with React >=16.9.0)."]})}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsxs)(n.p,{children:["If you receive warnings related to ",(0,i.jsx)(n.code,{children:"act()"})," function consult our ",(0,i.jsx)(n.a,{href:"/react-native-testing-library/docs/understanding-act",children:"Undestanding Act"})," function document."]})}),"\n",(0,i.jsxs)(n.h3,{id:"within-getqueriesforelement",children:[(0,i.jsx)(n.code,{children:"within"}),", ",(0,i.jsx)(n.code,{children:"getQueriesForElement"})]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"https://github.com/callstack/react-native-testing-library/blob/main/src/__tests__/within.test.tsx",children:(0,i.jsx)(n.code,{children:"Example code"})})}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"Defined as:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-jsx",children:"function within(element: ReactTestInstance): Queries {}\n\nfunction getQueriesForElement(element: ReactTestInstance): Queries {}\n"})}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.code,{children:"within"})," (also available as ",(0,i.jsx)(n.code,{children:"getQueriesForElement"})," alias) performs ",(0,i.jsx)(n.a,{href:"/react-native-testing-library/docs/api-queries",children:"queries"})," scoped to given element."]}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsxs)(n.p,{children:["Please note that additional ",(0,i.jsx)(n.code,{children:"render"})," specific operations like ",(0,i.jsx)(n.code,{children:"update"}),", ",(0,i.jsx)(n.code,{children:"unmount"}),", ",(0,i.jsx)(n.code,{children:"debug"}),", ",(0,i.jsx)(n.code,{children:"toJSON"})," are ",(0,i.jsx)(n.em,{children:"not"})," included."]})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-jsx",children:"const detailsScreen = within(screen.getByA11yHint('Details Screen'));\nexpect(detailsScreen.getByText('Some Text')).toBeOnTheScreen();\nexpect(detailsScreen.getByDisplayValue('Some Value')).toBeOnTheScreen();\nexpect(detailsScreen.queryByLabelText('Some Label')).toBeOnTheScreen();\nawait expect(detailsScreen.findByA11yHint('Some Label')).resolves.toBeOnTheScreen();\n"})}),"\n",(0,i.jsx)(n.p,{children:"Use cases for scoped queries include:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"queries scoped to a single item inside a FlatList containing many items"}),"\n",(0,i.jsx)(n.li,{children:"queries scoped to a single screen in tests involving screen transitions (e.g. with react-navigation)"}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"act",children:(0,i.jsx)(n.code,{children:"act"})}),"\n",(0,i.jsxs)(n.p,{children:["Useful function to help testing components that use hooks API. By default any ",(0,i.jsx)(n.code,{children:"render"}),", ",(0,i.jsx)(n.code,{children:"update"}),", ",(0,i.jsx)(n.code,{children:"fireEvent"}),", and ",(0,i.jsx)(n.code,{children:"waitFor"})," calls are wrapped by this function, so there is no need to wrap it manually. This method is re-exported from ",(0,i.jsx)(n.a,{href:"https://github.com/facebook/react/blob/main/packages/react-test-renderer/src/ReactTestRenderer.js#L567%5D",children:(0,i.jsx)(n.code,{children:"react-test-renderer"})}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["Consult our ",(0,i.jsx)(n.a,{href:"/react-native-testing-library/docs/understanding-act",children:"Undestanding Act function"})," document for more understanding of its intricacies."]}),"\n",(0,i.jsx)(n.h3,{id:"cleanup",children:(0,i.jsx)(n.code,{children:"cleanup"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"const cleanup: () => void;\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Unmounts React trees that were mounted with ",(0,i.jsx)(n.code,{children:"render"})," and clears ",(0,i.jsx)(n.code,{children:"screen"})," variable that holds latest ",(0,i.jsx)(n.code,{children:"render"})," output."]}),"\n",(0,i.jsx)(n.admonition,{type:"info",children:(0,i.jsxs)(n.p,{children:["Please note that this is done automatically if the testing framework you're using supports the ",(0,i.jsx)(n.code,{children:"afterEach"})," global (like mocha, Jest, and Jasmine). If not, you will need to do manual cleanups after each test."]})}),"\n",(0,i.jsxs)(n.p,{children:["For example, if you're using the ",(0,i.jsx)(n.code,{children:"jest"})," testing framework, then you would need to use the ",(0,i.jsx)(n.code,{children:"afterEach"})," hook like so:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-jsx",children:"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"})}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"afterEach(cleanup)"})," call also works in ",(0,i.jsx)(n.code,{children:"describe"})," blocks:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-jsx",children:"describe('when logged in', () => {\n afterEach(cleanup);\n\n it('renders the user', () => {\n render();\n // ...\n });\n});\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Failing to call ",(0,i.jsx)(n.code,{children:"cleanup"})," when you've called ",(0,i.jsx)(n.code,{children:"render"}),' could result in a memory leak and tests which are not "idempotent" (which can lead to difficult to debug errors in your tests).']}),"\n",(0,i.jsxs)(n.h2,{id:"renderhook-api",children:[(0,i.jsx)(n.code,{children:"renderHook"})," API"]}),"\n",(0,i.jsx)(n.p,{children:"Defined as:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"function renderHook(\n callback: (props?: Props) => Result,\n options?: RenderHookOptions,\n): RenderHookResult;\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Renders a test component that will call the provided ",(0,i.jsx)(n.code,{children:"callback"}),", including any hooks it calls, every time it renders. Returns ",(0,i.jsx)(n.a,{href:"#renderhookresult-object",children:(0,i.jsx)(n.code,{children:"RenderHookResult"})})," object, which you can interact with."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"import { renderHook } from '@testing-library/react-native';\nimport { useCount } from '../useCount';\n\nit('should increment count', () => {\n const { result } = renderHook(() => useCount());\n\n expect(result.current.count).toBe(0);\n act(() => {\n // Note that you should wrap the calls to functions your hook returns with `act` if they trigger an update of your hook's state to ensure pending useEffects are run before your next assertion.\n result.current.increment();\n });\n expect(result.current.count).toBe(1);\n});\n"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"// useCount.js\nexport const useCount = () => {\n const [count, setCount] = useState(0);\n const increment = () => setCount((previousCount) => previousCount + 1);\n\n return { count, increment };\n};\n"})}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"renderHook"})," function accepts the following arguments:"]}),"\n",(0,i.jsxs)(n.p,{children:["Callback is a function that is called each ",(0,i.jsx)(n.code,{children:"render"})," of the test component. This function should call one or more hooks for testing."]}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"props"})," passed into the callback will be the ",(0,i.jsx)(n.code,{children:"initialProps"})," provided in the ",(0,i.jsx)(n.code,{children:"options"})," to ",(0,i.jsx)(n.code,{children:"renderHook"}),", unless new props are provided by a subsequent ",(0,i.jsx)(n.code,{children:"rerender"})," call."]}),"\n",(0,i.jsx)(n.h3,{id:"options",children:(0,i.jsx)(n.code,{children:"options"})}),"\n",(0,i.jsxs)(n.p,{children:["A ",(0,i.jsx)(n.code,{children:"RenderHookOptions"})," object to modify the execution of the ",(0,i.jsx)(n.code,{children:"callback"})," function, containing the following properties:"]}),"\n",(0,i.jsx)(n.h4,{id:"initialprops",children:(0,i.jsx)(n.code,{children:"initialProps"})}),"\n",(0,i.jsxs)(n.p,{children:["The initial values to pass as ",(0,i.jsx)(n.code,{children:"props"})," to the ",(0,i.jsx)(n.code,{children:"callback"})," function of ",(0,i.jsx)(n.code,{children:"renderHook"}),". The ",(0,i.jsx)(n.code,{children:"Props"})," type is determined by the type passed to or inferred by the ",(0,i.jsx)(n.code,{children:"renderHook"})," call."]}),"\n",(0,i.jsx)(n.h4,{id:"wrapper",children:(0,i.jsx)(n.code,{children:"wrapper"})}),"\n",(0,i.jsxs)(n.p,{children:["A React component to wrap the test component in when rendering. This is usually used to add context providers from ",(0,i.jsx)(n.code,{children:"React.createContext"})," for the hook to access with ",(0,i.jsx)(n.code,{children:"useContext"}),"."]}),"\n",(0,i.jsx)(n.h3,{id:"renderhookresult",children:(0,i.jsx)(n.code,{children:"RenderHookResult"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"interface RenderHookResult {\n result: { current: Result };\n rerender: (props: Props) => void;\n unmount: () => void;\n}\n"})}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"renderHook"})," function returns an object that has the following properties:"]}),"\n",(0,i.jsx)(n.h3,{id:"result",children:(0,i.jsx)(n.code,{children:"result"})}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"current"})," value of the ",(0,i.jsx)(n.code,{children:"result"})," will reflect the latest of whatever is returned from the ",(0,i.jsx)(n.code,{children:"callback"})," passed to ",(0,i.jsx)(n.code,{children:"renderHook"}),". The ",(0,i.jsx)(n.code,{children:"Result"})," type is determined by the type passed to or inferred by the ",(0,i.jsx)(n.code,{children:"renderHook"})," call."]}),"\n",(0,i.jsx)(n.h3,{id:"rerender",children:(0,i.jsx)(n.code,{children:"rerender"})}),"\n",(0,i.jsxs)(n.p,{children:["A function to rerender the test component, causing any hooks to be recalculated. If ",(0,i.jsx)(n.code,{children:"newProps"})," are passed, they will replace the ",(0,i.jsx)(n.code,{children:"callback"})," function's ",(0,i.jsx)(n.code,{children:"initialProps"})," for subsequent rerenders. The ",(0,i.jsx)(n.code,{children:"Props"})," type is determined by the type passed to or inferred by the ",(0,i.jsx)(n.code,{children:"renderHook"})," call."]}),"\n",(0,i.jsx)(n.h3,{id:"unmount-1",children:(0,i.jsx)(n.code,{children:"unmount"})}),"\n",(0,i.jsxs)(n.p,{children:["A function to unmount the test component. This is commonly used to trigger cleanup effects for ",(0,i.jsx)(n.code,{children:"useEffect"})," hooks."]}),"\n",(0,i.jsx)(n.h3,{id:"examples",children:"Examples"}),"\n",(0,i.jsxs)(n.p,{children:["Here we present some extra examples of using ",(0,i.jsx)(n.code,{children:"renderHook"})," API."]}),"\n",(0,i.jsxs)(n.h4,{id:"with-initialprops",children:["With ",(0,i.jsx)(n.code,{children:"initialProps"})]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"const useCount = (initialCount: number) => {\n const [count, setCount] = useState(initialCount);\n const increment = () => setCount((previousCount) => previousCount + 1);\n\n useEffect(() => {\n setCount(initialCount);\n }, [initialCount]);\n\n return { count, increment };\n};\n\nit('should increment count', () => {\n const { result, rerender } = renderHook((initialCount: number) => useCount(initialCount), {\n initialProps: 1,\n });\n\n expect(result.current.count).toBe(1);\n\n act(() => {\n result.current.increment();\n });\n\n expect(result.current.count).toBe(2);\n rerender(5);\n expect(result.current.count).toBe(5);\n});\n"})}),"\n",(0,i.jsxs)(n.h4,{id:"with-wrapper",children:["With ",(0,i.jsx)(n.code,{children:"wrapper"})]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-tsx",children:"it('should use context value', () => {\n function Wrapper({ children }: { children: ReactNode }) {\n return {children};\n }\n\n const { result } = renderHook(() => useHook(), { wrapper: Wrapper });\n // ...\n});\n"})}),"\n",(0,i.jsx)(n.h2,{id:"configuration",children:"Configuration"}),"\n",(0,i.jsx)(n.h3,{id:"configure",children:(0,i.jsx)(n.code,{children:"configure"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"type Config = {\n asyncUtilTimeout: number;\n defaultHidden: boolean;\n defaultDebugOptions: Partial;\n};\n\nfunction configure(options: Partial) {}\n"})}),"\n",(0,i.jsxs)(n.h4,{id:"asyncutiltimeout-option",children:[(0,i.jsx)(n.code,{children:"asyncUtilTimeout"})," option"]}),"\n",(0,i.jsxs)(n.p,{children:["Default timeout, in ms, for async helper functions (",(0,i.jsx)(n.code,{children:"waitFor"}),", ",(0,i.jsx)(n.code,{children:"waitForElementToBeRemoved"}),") and ",(0,i.jsx)(n.code,{children:"findBy*"})," queries. Defaults to 1000 ms."]}),"\n",(0,i.jsxs)(n.h4,{id:"defaultincludehiddenelements-option",children:[(0,i.jsx)(n.code,{children:"defaultIncludeHiddenElements"})," option"]}),"\n",(0,i.jsxs)(n.p,{children:["Default value for ",(0,i.jsx)(n.a,{href:"/react-native-testing-library/docs/api-queries#includehiddenelements-option",children:"includeHiddenElements"})," query option for all queries. The default value is set to ",(0,i.jsx)(n.code,{children:"false"}),", so all queries will not match ",(0,i.jsx)(n.a,{href:"#ishiddenfromaccessibility",children:"elements hidden from accessibility"}),". This is because the users of the app would not be able to see such elements."]}),"\n",(0,i.jsxs)(n.p,{children:["This option is also available as ",(0,i.jsx)(n.code,{children:"defaultHidden"})," alias for compatibility with ",(0,i.jsx)(n.a,{href:"https://testing-library.com/docs/dom-testing-library/api-configuration/#defaulthidden",children:"React Testing Library"}),"."]}),"\n",(0,i.jsxs)(n.h4,{id:"defaultdebugoptions-option",children:[(0,i.jsx)(n.code,{children:"defaultDebugOptions"})," option"]}),"\n",(0,i.jsxs)(n.p,{children:["Default ",(0,i.jsx)(n.a,{href:"#debug",children:"debug options"})," to be used when calling ",(0,i.jsx)(n.code,{children:"debug()"}),". These default options will be overridden by the ones you specify directly when calling ",(0,i.jsx)(n.code,{children:"debug()"}),"."]}),"\n",(0,i.jsx)(n.h3,{id:"resettodefaults",children:(0,i.jsx)(n.code,{children:"resetToDefaults()"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"function resetToDefaults() {}\n"})}),"\n",(0,i.jsx)(n.h3,{id:"environment-variables",children:"Environment variables"}),"\n",(0,i.jsx)(n.h4,{id:"rntl_skip_auto_cleanup",children:(0,i.jsx)(n.code,{children:"RNTL_SKIP_AUTO_CLEANUP"})}),"\n",(0,i.jsxs)(n.p,{children:["Set to ",(0,i.jsx)(n.code,{children:"true"})," to disable automatic ",(0,i.jsx)(n.code,{children:"cleanup()"})," after each test. It works the same as importing ",(0,i.jsx)(n.code,{children:"react-native-testing-library/dont-cleanup-after-each"})," or using ",(0,i.jsx)(n.code,{children:"react-native-testing-library/pure"}),"."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-shell",children:"$ RNTL_SKIP_AUTO_CLEANUP=true jest\n"})}),"\n",(0,i.jsx)(n.h4,{id:"rntl_skip_auto_detect_fake_timers",children:(0,i.jsx)(n.code,{children:"RNTL_SKIP_AUTO_DETECT_FAKE_TIMERS"})}),"\n",(0,i.jsxs)(n.p,{children:["Set to ",(0,i.jsx)(n.code,{children:"true"})," to disable auto-detection of fake timers. This might be useful in rare cases when you want to use non-Jest fake timers. See ",(0,i.jsx)(n.a,{href:"https://github.com/callstack/react-native-testing-library/issues/886",children:"issue #886"})," for more details."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-shell",children:"$ RNTL_SKIP_AUTO_DETECT_FAKE_TIMERS=true jest\n"})}),"\n",(0,i.jsx)(n.h2,{id:"accessibility",children:"Accessibility"}),"\n",(0,i.jsx)(n.h3,{id:"ishiddenfromaccessibility",children:(0,i.jsx)(n.code,{children:"isHiddenFromAccessibility"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"function isHiddenFromAccessibility(\n element: ReactTestInstance | null\n): boolean {}\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Also available as ",(0,i.jsx)(n.code,{children:"isInaccessible()"})," alias for React Testing Library compatibility."]}),"\n",(0,i.jsx)(n.p,{children:"Checks if given element is hidden from assistive technology, e.g. screen readers."}),"\n",(0,i.jsxs)(n.admonition,{type:"note",children:[(0,i.jsxs)(n.p,{children:["Like ",(0,i.jsx)(n.a,{href:"https://testing-library.com/docs/dom-testing-library/api-accessibility/#isinaccessible",children:(0,i.jsx)(n.code,{children:"isInaccessible"})})," function from DOM Testing Library this function considers both accessibility elements and presentational elements (regular ",(0,i.jsx)(n.code,{children:"View"}),"s) to be accessible, unless they are hidden in terms of host platform."]}),(0,i.jsxs)(n.p,{children:["This covers only part of ",(0,i.jsx)(n.a,{href:"https://www.w3.org/TR/wai-aria-1.2/#tree_exclusion",children:"ARIA notion of Accessiblity Tree"}),", as ARIA excludes both hidden and presentational elements from the Accessibility Tree."]})]}),"\n",(0,i.jsx)(n.p,{children:"For the scope of this function, element is inaccessible when it, or any of its ancestors, meets any of the following conditions:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["it has ",(0,i.jsx)(n.code,{children:"display: none"})," style"]}),"\n",(0,i.jsxs)(n.li,{children:["it has ",(0,i.jsx)(n.a,{href:"https://reactnative.dev/docs/accessibility#aria-hidden",children:(0,i.jsx)(n.code,{children:"aria-hidden"})})," prop set to ",(0,i.jsx)(n.code,{children:"true"})]}),"\n",(0,i.jsxs)(n.li,{children:["it has ",(0,i.jsx)(n.a,{href:"https://reactnative.dev/docs/accessibility#accessibilityelementshidden-ios",children:(0,i.jsx)(n.code,{children:"accessibilityElementsHidden"})})," prop set to ",(0,i.jsx)(n.code,{children:"true"})]}),"\n",(0,i.jsxs)(n.li,{children:["it has ",(0,i.jsx)(n.a,{href:"https://reactnative.dev/docs/accessibility#importantforaccessibility-android",children:(0,i.jsx)(n.code,{children:"importantForAccessibility"})})," prop set to ",(0,i.jsx)(n.code,{children:"no-hide-descendants"})]}),"\n",(0,i.jsxs)(n.li,{children:["it has sibling host element with either ",(0,i.jsx)(n.a,{href:"https://reactnative.dev/docs/accessibility#aria-modal-ios",children:(0,i.jsx)(n.code,{children:"aria-modal"})})," or ",(0,i.jsx)(n.a,{href:"https://reactnative.dev/docs/accessibility#accessibilityviewismodal-ios",children:(0,i.jsx)(n.code,{children:"accessibilityViewIsModal"})})," prop set to ",(0,i.jsx)(n.code,{children:"true"})]}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["Specifying ",(0,i.jsx)(n.code,{children:"accessible={false}"}),", ",(0,i.jsx)(n.code,{children:'accessiblityRole="none"'}),", or ",(0,i.jsx)(n.code,{children:'importantForAccessibility="no"'})," props does not cause the element to become inaccessible."]})]})}function u(e={}){const{wrapper:n}={...(0,s.a)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(h,{...e})}):h(e)}},1151:(e,n,t)=>{t.d(n,{Z:()=>c,a:()=>o});var i=t(7294);const s={},r=i.createContext(s);function o(e){const n=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function c(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:o(e.components),i.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/c8229a80.87ec1e8f.js b/assets/js/c8229a80.87ec1e8f.js deleted file mode 100644 index 94911982..00000000 --- a/assets/js/c8229a80.87ec1e8f.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkreact_native_testing_library_website=self.webpackChunkreact_native_testing_library_website||[]).push([[298],{2063:(e,n,t)=>{t.d(n,{Z:()=>o});t(7294);var i=t(1351);const s={tableOfContentsInline:"tableOfContentsInline_prmo"};var r=t(5893);function o(e){let{toc:n,minHeadingLevel:t,maxHeadingLevel:o}=e;return(0,r.jsx)("div",{className:s.tableOfContentsInline,children:(0,r.jsx)(i.Z,{toc:n,minHeadingLevel:t,maxHeadingLevel:o,className:"table-of-contents",linkClassName:null})})}},1351:(e,n,t)=>{t.d(n,{Z:()=>m});var i=t(7294),s=t(6793);function r(e){const n=e.map((e=>({...e,parentIndex:-1,children:[]}))),t=Array(7).fill(-1);n.forEach(((e,n)=>{const i=t.slice(2,e.level);e.parentIndex=Math.max(...i),t[e.level]=n}));const i=[];return n.forEach((e=>{const{parentIndex:t,...s}=e;t>=0?n[t].children.push(s):i.push(s)})),i}function o(e){let{toc:n,minHeadingLevel:t,maxHeadingLevel:i}=e;return n.flatMap((e=>{const n=o({toc:e.children,minHeadingLevel:t,maxHeadingLevel:i});return function(e){return e.level>=t&&e.level<=i}(e)?[{...e,children:n}]:n}))}function c(e){const n=e.getBoundingClientRect();return n.top===n.bottom?c(e.parentNode):n}function l(e,n){var t;let{anchorTopOffset:i}=n;const s=e.find((e=>c(e).top>=i));if(s){var r;return function(e){return e.top>0&&e.bottom{e.current=n?0:document.querySelector(".navbar").clientHeight}),[n]),e}function d(e){const n=(0,i.useRef)(void 0),t=a();(0,i.useEffect)((()=>{if(!e)return()=>{};const{linkClassName:i,linkActiveClassName:s,minHeadingLevel:r,maxHeadingLevel:o}=e;function c(){const e=function(e){return Array.from(document.getElementsByClassName(e))}(i),c=function(e){let{minHeadingLevel:n,maxHeadingLevel:t}=e;const i=[];for(let s=n;s<=t;s+=1)i.push("h"+s+".anchor");return Array.from(document.querySelectorAll(i.join()))}({minHeadingLevel:r,maxHeadingLevel:o}),a=l(c,{anchorTopOffset:t.current}),d=e.find((e=>a&&a.id===function(e){return decodeURIComponent(e.href.substring(e.href.indexOf("#")+1))}(e)));e.forEach((e=>{!function(e,t){t?(n.current&&n.current!==e&&n.current.classList.remove(s),e.classList.add(s),n.current=e):e.classList.remove(s)}(e,e===d)}))}return document.addEventListener("scroll",c),document.addEventListener("resize",c),c(),()=>{document.removeEventListener("scroll",c),document.removeEventListener("resize",c)}}),[e,t])}var h=t(8746),u=t(5893);function p(e){let{toc:n,className:t,linkClassName:i,isChild:s}=e;return n.length?(0,u.jsx)("ul",{className:s?void 0:t,children:n.map((e=>(0,u.jsxs)("li",{children:[(0,u.jsx)(h.Z,{to:"#"+e.id,className:null!=i?i:void 0,dangerouslySetInnerHTML:{__html:e.value}}),(0,u.jsx)(p,{isChild:!0,toc:e.children,className:t,linkClassName:i})]},e.id)))}):null}const x=i.memo(p);function m(e){let{toc:n,className:t="table-of-contents table-of-contents__left-border",linkClassName:c="table-of-contents__link",linkActiveClassName:l,minHeadingLevel:a,maxHeadingLevel:h,...p}=e;const m=(0,s.L)(),j=null!=a?a:m.tableOfContents.minHeadingLevel,f=null!=h?h:m.tableOfContents.maxHeadingLevel,g=function(e){let{toc:n,minHeadingLevel:t,maxHeadingLevel:s}=e;return(0,i.useMemo)((()=>o({toc:r(n),minHeadingLevel:t,maxHeadingLevel:s})),[n,t,s])}({toc:n,minHeadingLevel:j,maxHeadingLevel:f});return d((0,i.useMemo)((()=>{if(c&&l)return{linkClassName:c,linkActiveClassName:l,minHeadingLevel:j,maxHeadingLevel:f}}),[c,l,j,f])),(0,u.jsx)(x,{toc:g,className:t,linkClassName:c,...p})}},1804:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>a,contentTitle:()=>c,default:()=>u,frontMatter:()=>o,metadata:()=>l,toc:()=>d});var i=t(5893),s=t(1151),r=t(2063);const o={id:"api",title:"API"},c=void 0,l={id:"api",title:"API",description:"render API",source:"@site/docs/API.md",sourceDirName:".",slug:"/api",permalink:"/react-native-testing-library/docs/api",draft:!1,unlisted:!1,editUrl:"https://github.com/callstack/react-native-testing-library/blob/main/website/docs/API.md",tags:[],version:"current",frontMatter:{id:"api",title:"API"},sidebar:"docs",previous:{title:"Getting Started",permalink:"/react-native-testing-library/docs/getting-started"},next:{title:"Queries",permalink:"/react-native-testing-library/docs/api-queries"}},a={},d=[{value:"render API",id:"render-api",level:2},{value:"Options",id:"render-options",level:3},{value:"wrapper option",id:"wrapper-option",level:4},{value:"createNodeMock option",id:"createnodemock-option",level:4},{value:"unstable_validateStringsRenderedWithinText option",id:"unstable_validatestringsrenderedwithintext-option",level:4},{value:"...queries",id:"queries",level:3},{value:"Example",id:"example",level:4},{value:"update",id:"update",level:3},{value:"unmount",id:"unmount",level:3},{value:"debug",id:"debug",level:3},{value:"message option",id:"message-option",level:4},{value:"mapProps option",id:"mapprops-option",level:4},{value:"debug.shallow",id:"debugshallow",level:4},{value:"toJSON",id:"tojson",level:3},{value:"root",id:"root",level:3},{value:"UNSAFE_root",id:"unsafe_root",level:3},{value:"screen API",id:"screen-api",level:2},{value:"fireEvent API",id:"fireevent-api",level:2},{value:"fireEvent.press",id:"fireeventpress",level:3},{value:"fireEvent.changeText",id:"fireeventchangetext",level:3},{value:"fireEvent.scroll",id:"fireeventscroll",level:3},{value:"On a ScrollView",id:"on-a-scrollview",level:4},{value:"Helper functions",id:"helper-functions",level:2},{value:"waitFor",id:"waitfor",level:3},{value:"Using a React Native version < 0.71 with Jest fake timers",id:"using-a-react-native-version--071-with-jest-fake-timers",level:4},{value:"waitForElementToBeRemoved",id:"waitforelementtoberemoved",level:3},{value:"within, getQueriesForElement",id:"within-getqueriesforelement",level:3},{value:"act",id:"act",level:3},{value:"cleanup",id:"cleanup",level:3},{value:"renderHook API",id:"renderhook-api",level:2},{value:"options",id:"options",level:3},{value:"initialProps",id:"initialprops",level:4},{value:"wrapper",id:"wrapper",level:4},{value:"RenderHookResult",id:"renderhookresult",level:3},{value:"result",id:"result",level:3},{value:"rerender",id:"rerender",level:3},{value:"unmount",id:"unmount-1",level:3},{value:"Examples",id:"examples",level:3},{value:"With initialProps",id:"with-initialprops",level:4},{value:"With wrapper",id:"with-wrapper",level:4},{value:"Configuration",id:"configuration",level:2},{value:"configure",id:"configure",level:3},{value:"asyncUtilTimeout option",id:"asyncutiltimeout-option",level:4},{value:"defaultIncludeHiddenElements option",id:"defaultincludehiddenelements-option",level:4},{value:"defaultDebugOptions option",id:"defaultdebugoptions-option",level:4},{value:"resetToDefaults()",id:"resettodefaults",level:3},{value:"Environment variables",id:"environment-variables",level:3},{value:"RNTL_SKIP_AUTO_CLEANUP",id:"rntl_skip_auto_cleanup",level:4},{value:"RNTL_SKIP_AUTO_DETECT_FAKE_TIMERS",id:"rntl_skip_auto_detect_fake_timers",level:4},{value:"Accessibility",id:"accessibility",level:2},{value:"isHiddenFromAccessibility",id:"ishiddenfromaccessibility",level:3}];function h(e){const n={a:"a",admonition:"admonition",blockquote:"blockquote",code:"code",em:"em",h2:"h2",h3:"h3",h4:"h4",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(r.Z,{toc:d}),"\n",(0,i.jsxs)(n.h2,{id:"render-api",children:[(0,i.jsx)(n.code,{children:"render"})," API"]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"https://github.com/callstack/react-native-testing-library/blob/main/src/__tests__/render.test.tsx",children:(0,i.jsx)(n.code,{children:"Example code"})})}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"Defined as:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-jsx",children:"function render(\n component: React.Element,\n options?: RenderOptions\n): RenderResult {}\n"})}),"\n",(0,i.jsx)(n.p,{children:"Deeply renders given React element and returns helpers to query the output components structure."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-jsx",children:"import { render } from '@testing-library/react-native';\nimport { QuestionsBoard } from '../QuestionsBoard';\n\ntest('should verify two questions', () => {\n render();\n const allQuestions = screen.queryAllByRole('header');\n\n expect(allQuestions).toHaveLength(2);\n});\n"})}),"\n",(0,i.jsxs)(n.blockquote,{children:["\n",(0,i.jsxs)(n.p,{children:["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 ",(0,i.jsx)(n.code,{children:"render"})," method. ",(0,i.jsx)(n.a,{href:"https://testing-library.com/docs/react-testing-library/setup#custom-render",children:"Follow this great guide on how to set this up"}),"."]}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"render"})," method returns a ",(0,i.jsx)(n.code,{children:"RenderResult"})," object having properties described below."]}),"\n",(0,i.jsxs)(n.admonition,{type:"info",children:[(0,i.jsxs)(n.p,{children:["Latest ",(0,i.jsx)(n.code,{children:"render"})," result is kept in ",(0,i.jsx)(n.a,{href:"#screen",children:(0,i.jsx)(n.code,{children:"screen"})})," variable that can be imported from ",(0,i.jsx)(n.code,{children:"@testing-library/react-native"})," package."]}),(0,i.jsxs)(n.p,{children:["Using ",(0,i.jsx)(n.code,{children:"screen"})," instead of destructuring ",(0,i.jsx)(n.code,{children:"render"})," result is recommended approach. See ",(0,i.jsx)(n.a,{href:"https://kentcdodds.com/blog/common-mistakes-with-react-testing-library#not-using-screen",children:"this article"})," from Kent C. Dodds for more details."]})]}),"\n",(0,i.jsx)(n.h3,{id:"render-options",children:"Options"}),"\n",(0,i.jsxs)(n.p,{children:["The behavior of ",(0,i.jsx)(n.code,{children:"render"})," method can be customized by passing various options as a second argument of ",(0,i.jsx)(n.code,{children:"RenderOptions"})," type:"]}),"\n",(0,i.jsxs)(n.h4,{id:"wrapper-option",children:[(0,i.jsx)(n.code,{children:"wrapper"})," option"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"wrapper?: React.ComponentType,\n"})}),"\n",(0,i.jsxs)(n.p,{children:["This options allows you to wrap tested component, passed as the first option to the ",(0,i.jsx)(n.code,{children:"render()"})," function, in additional wrapper component. This is most useful for creating reusable custom render functions for common React Context providers."]}),"\n",(0,i.jsxs)(n.h4,{id:"createnodemock-option",children:[(0,i.jsx)(n.code,{children:"createNodeMock"})," option"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"createNodeMock?: (element: React.Element) => any,\n"})}),"\n",(0,i.jsxs)(n.p,{children:["This options allows you to pass ",(0,i.jsx)(n.code,{children:"createNodeMock"})," option to ",(0,i.jsx)(n.code,{children:"ReactTestRenderer.create()"})," method in order to allow for custom mock refs. You can learn more about this options from ",(0,i.jsx)(n.a,{href:"https://reactjs.org/docs/test-renderer.html#ideas",children:"React Test Renderer documentation"}),"."]}),"\n",(0,i.jsxs)(n.h4,{id:"unstable_validatestringsrenderedwithintext-option",children:[(0,i.jsx)(n.code,{children:"unstable_validateStringsRenderedWithinText"})," option"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"unstable_validateStringsRenderedWithinText?: boolean;\n"})}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsxs)(n.p,{children:["This options is experimental, in some cases it might not work as intended, and its behavior might change without observing ",(0,i.jsx)(n.a,{href:"https://semver.org/",children:"SemVer"})," requirements for breaking changes."]})}),"\n",(0,i.jsxs)(n.p,{children:["This ",(0,i.jsx)(n.strong,{children:"experimental"})," option allows you to replicate React Native behavior of throwing ",(0,i.jsx)(n.code,{children:"Invariant Violation: Text strings must be rendered within a component"})," error when you try to render ",(0,i.jsx)(n.code,{children:"string"})," value under components different than ",(0,i.jsx)(n.code,{children:""}),", e.g. under ",(0,i.jsx)(n.code,{children:""}),"."]}),"\n",(0,i.jsx)(n.p,{children:"This check is not enforced by React Test Renderer and hence by default React Native Testing Library also does not check this. That might result in runtime errors when running your code on a device, while the code works without errors in tests."}),"\n",(0,i.jsx)(n.h3,{id:"queries",children:(0,i.jsx)(n.code,{children:"...queries"})}),"\n",(0,i.jsxs)(n.p,{children:["The most important feature of ",(0,i.jsx)(n.code,{children:"render"})," is providing a set of helpful queries that allow you to find certain elements in the view hierarchy."]}),"\n",(0,i.jsxs)(n.p,{children:["See ",(0,i.jsx)(n.a,{href:"/react-native-testing-library/docs/api-queries",children:"Queries"})," for a complete list."]}),"\n",(0,i.jsx)(n.h4,{id:"example",children:"Example"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-jsx",children:"import { render } from '@testing-library/react-native';\n\nconst { getByText, queryByA11yState } = render();\n"})}),"\n",(0,i.jsx)(n.h3,{id:"update",children:(0,i.jsx)(n.code,{children:"update"})}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsxs)(n.em,{children:["Also available under ",(0,i.jsx)(n.code,{children:"rerender"})," alias"]})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"update(element: React.Element): void\nrerender(element: React.Element): void\n"})}),"\n",(0,i.jsxs)(n.p,{children:["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 ",(0,i.jsx)(n.code,{children:"componentDidUpdate"})," behavior, by passing updated props to the component."]}),"\n",(0,i.jsx)(n.p,{children:(0,i.jsx)(n.a,{href:"https://github.com/callstack/react-native-testing-library/blob/f96d782d26dd4815dbfd01de6ef7a647efd1f693/src/__tests__/act.test.js#L31-L37",children:"Example code"})}),"\n",(0,i.jsx)(n.h3,{id:"unmount",children:(0,i.jsx)(n.code,{children:"unmount"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"unmount(): void\n"})}),"\n",(0,i.jsx)(n.p,{children:"Unmount the in-memory tree, triggering the appropriate lifecycle events."}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsxs)(n.p,{children:["Usually you should not need to call ",(0,i.jsx)(n.code,{children:"unmount"})," as it is done automatically if your test runner supports ",(0,i.jsx)(n.code,{children:"afterEach"})," hook (like Jest, mocha, Jasmine)."]})}),"\n",(0,i.jsx)(n.h3,{id:"debug",children:(0,i.jsx)(n.code,{children:"debug"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"interface DebugOptions {\n message?: string;\n mapProps?: MapPropsFunction;\n}\n\ndebug(options?: DebugOptions | string): void\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Pretty prints deeply rendered component passed to ",(0,i.jsx)(n.code,{children:"render"}),"."]}),"\n",(0,i.jsxs)(n.h4,{id:"message-option",children:[(0,i.jsx)(n.code,{children:"message"})," option"]}),"\n",(0,i.jsx)(n.p,{children:"You can provide a message that will be printed on top."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-jsx",children:"render();\nscreen.debug({ message: 'optional message' });\n"})}),"\n",(0,i.jsx)(n.p,{children:"logs optional message and colored JSX:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-jsx",children:"optional message\n\n\n Press me\n\n"})}),"\n",(0,i.jsxs)(n.h4,{id:"mapprops-option",children:[(0,i.jsx)(n.code,{children:"mapProps"})," option"]}),"\n",(0,i.jsxs)(n.p,{children:["You can use the ",(0,i.jsx)(n.code,{children:"mapProps"})," option to transform the props that will be printed :"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-jsx",children:"render();\ndebug({ mapProps: ({ style, ...props }) => ({ props }) });\n"})}),"\n",(0,i.jsxs)(n.p,{children:["This will log the rendered JSX without the ",(0,i.jsx)(n.code,{children:"style"})," props."]}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"children"})," prop cannot be filtered out so the following will print all rendered components with all props but ",(0,i.jsx)(n.code,{children:"children"})," filtered out."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"debug({ mapProps: (props) => ({}) });\n"})}),"\n",(0,i.jsxs)(n.p,{children:["This option can be used to target specific props when debugging a query (for instance keeping only ",(0,i.jsx)(n.code,{children:"children"})," prop when debugging a ",(0,i.jsx)(n.code,{children:"getByText"})," query)."]}),"\n",(0,i.jsx)(n.p,{children:"You can also transform prop values so that they are more readable (e.g. flatten styles)."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"import { StyleSheet } from 'react-native';\n\ndebug({ mapProps : {({ style, ...props })} => ({ style : StyleSheet.flatten(style), ...props }) });\n"})}),"\n",(0,i.jsx)(n.p,{children:"Or remove props that have little value when debugging tests, e.g. path prop for svgs"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"debug({ mapProps: ({ path, ...props }) => ({ ...props }) });\n"})}),"\n",(0,i.jsx)(n.h4,{id:"debugshallow",children:(0,i.jsx)(n.code,{children:"debug.shallow"})}),"\n",(0,i.jsxs)(n.p,{children:["Pretty prints shallowly rendered component passed to ",(0,i.jsx)(n.code,{children:"render"})," with optional message on top."]}),"\n",(0,i.jsx)(n.h3,{id:"tojson",children:(0,i.jsx)(n.code,{children:"toJSON"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"toJSON(): ReactTestRendererJSON | null\n"})}),"\n",(0,i.jsx)(n.p,{children:"Get the rendered component JSON representation, e.g. for snapshot testing."}),"\n",(0,i.jsx)(n.h3,{id:"root",children:(0,i.jsx)(n.code,{children:"root"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"root: ReactTestInstance;\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Returns the rendered root ",(0,i.jsx)(n.a,{href:"testing-env#host-and-composite-components",children:"host element"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["This API is primarily useful in component tests, as it allows you to access root host view without using ",(0,i.jsx)(n.code,{children:"*ByTestId"})," queries or similar methods."]}),"\n",(0,i.jsx)(n.h3,{id:"unsafe_root",children:(0,i.jsx)(n.code,{children:"UNSAFE_root"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"UNSAFE_root: ReactTestInstance;\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Returns the rendered ",(0,i.jsx)(n.a,{href:"testing-env#host-and-composite-components",children:"composite root element"}),"."]}),"\n",(0,i.jsx)(n.admonition,{type:"caution",children:(0,i.jsx)(n.p,{children:"This API typically will return a composite view which goes against recommended testing practices. This API is primarily available for legacy test suites that rely on such testing."})}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsxs)(n.p,{children:["This API has been previously named ",(0,i.jsx)(n.code,{children:"container"})," for compatibility with ",(0,i.jsx)(n.a,{href:"https://testing-library.com/docs/react-testing-library/api#container-1",children:"React Testing Library"}),". However, despite the same name, the actual behavior has been signficantly different, hence the name change to ",(0,i.jsx)(n.code,{children:"UNSAFE_root"}),"."]})}),"\n",(0,i.jsxs)(n.h2,{id:"screen-api",children:[(0,i.jsx)(n.code,{children:"screen"})," API"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"let screen: RenderResult;\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Hold the value of latest render call for easier access to query and other functions returned by ",(0,i.jsx)(n.a,{href:"#render",children:(0,i.jsx)(n.code,{children:"render"})}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["Its value is automatically cleared after each test by calling ",(0,i.jsx)(n.a,{href:"#cleanup",children:(0,i.jsx)(n.code,{children:"cleanup"})}),". If no ",(0,i.jsx)(n.code,{children:"render"})," call has been made in a given test then it holds a special object that implements ",(0,i.jsx)(n.code,{children:"RenderResult"})," but throws a helpful error on each property and method access."]}),"\n",(0,i.jsx)(n.p,{children:"This can also be used to build test utils that would normally require to be in render scope, either in a test file or globally for your project. For instance:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"// Prints the rendered components omitting all props except children.\nconst debugText = () => screen.debug({ mapProps: (props) => ({}) });\n"})}),"\n",(0,i.jsxs)(n.h2,{id:"fireevent-api",children:[(0,i.jsx)(n.code,{children:"fireEvent"})," API"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"function fireEvent(\n element: ReactTestInstance,\n eventName: string,\n ...data: Array\n): void {}\n"})}),"\n",(0,i.jsxs)(n.admonition,{type:"note",children:[(0,i.jsxs)(n.p,{children:["For common events like ",(0,i.jsx)(n.code,{children:"press"})," or ",(0,i.jsx)(n.code,{children:"type"})," it's recommended to use ",(0,i.jsx)(n.a,{href:"/react-native-testing-library/docs/user-event",children:"User Event API"})," as it offers\nmore realistic event simulation by emitting a sequence of events with proper event objects that mimic React Native runtime behavior."]}),(0,i.jsx)(n.p,{children:"Use Fire Event for cases not supported by User Event and for triggering event handlers on composite components."})]}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.code,{children:"fireEvent"})," API allows you to trigger all kind of event handlers on both host and composite components. It will try to invoke a single event handler traversing the component tree bottom-up from passed element and trying to find enabled event handler named ",(0,i.jsx)(n.code,{children:"onXxx"})," when ",(0,i.jsx)(n.code,{children:"xxx"})," is the name of the event passed."]}),"\n",(0,i.jsx)(n.p,{children:"Unlike User Event, this API does not automatically pass event object to event handler, this is responsibility of the user to construct such object."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-jsx",children:"import { render, screen, fireEvent } from '@testing-library/react-native';\n\ntest('fire changeText event', () => {\n const onEventMock = jest.fn();\n render(\n // MyComponent renders TextInput which has a placeholder 'Enter details'\n // and with `onChangeText` bound to handleChangeText\n \n );\n\n fireEvent(screen.getByPlaceholderText('change'), 'onChangeText', 'ab');\n expect(onEventMock).toHaveBeenCalledWith('ab');\n});\n"})}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsxs)(n.p,{children:["Please note that from version ",(0,i.jsx)(n.code,{children:"7.0"})," ",(0,i.jsx)(n.code,{children:"fireEvent"})," performs checks that should prevent events firing on disabled elements."]})}),"\n",(0,i.jsxs)(n.p,{children:["An example using ",(0,i.jsx)(n.code,{children:"fireEvent"})," with native events that aren't already aliased by the ",(0,i.jsx)(n.code,{children:"fireEvent"})," api."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-jsx",children:"import { TextInput, View } from 'react-native';\nimport { fireEvent, render } from '@testing-library/react-native';\n\nconst onBlurMock = jest.fn();\n\nrender(\n \n \n \n);\n\n// you can omit the `on` prefix\nfireEvent(screen.getByPlaceholderText('my placeholder'), 'blur');\n"})}),"\n",(0,i.jsxs)(n.p,{children:["FireEvent exposes convenience methods for common events like: ",(0,i.jsx)(n.code,{children:"press"}),", ",(0,i.jsx)(n.code,{children:"changeText"}),", ",(0,i.jsx)(n.code,{children:"scroll"}),"."]}),"\n",(0,i.jsx)(n.h3,{id:"fireeventpress",children:(0,i.jsx)(n.code,{children:"fireEvent.press"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:"fireEvent.press: (element: ReactTestInstance, ...data: Array) => void\n"})}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsxs)(n.p,{children:["It is recommended to use the User Event ",(0,i.jsx)(n.a,{href:"/react-native-testing-library/docs/user-event#press",children:(0,i.jsx)(n.code,{children:"press()"})})," helper instead as it offers more realistic simulation of press interaction, including pressable support."]})}),"\n",(0,i.jsxs)(n.p,{children:["Invokes ",(0,i.jsx)(n.code,{children:"press"})," event handler on the element or parent element in the tree."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-jsx",children:"import { View, Text, TouchableOpacity } from 'react-native';\nimport { render, screen, fireEvent } from '@testing-library/react-native';\n\nconst onPressMock = jest.fn();\nconst eventData = {\n nativeEvent: {\n pageX: 20,\n pageY: 30,\n },\n};\n\nrender(\n \n \n Press me\n \n \n);\n\nfireEvent.press(screen.getByText('Press me'), eventData);\nexpect(onPressMock).toHaveBeenCalledWith(eventData);\n"})}),"\n",(0,i.jsx)(n.h3,{id:"fireeventchangetext",children:(0,i.jsx)(n.code,{children:"fireEvent.changeText"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:"fireEvent.changeText: (element: ReactTestInstance, ...data: Array) => void\n"})}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsxs)(n.p,{children:["It is recommended to use the User Event ",(0,i.jsx)(n.a,{href:"/react-native-testing-library/docs/user-event#type",children:(0,i.jsx)(n.code,{children:"type()"})})," helper instead as it offers more realistic simulation of text change interaction, including key-by-key typing, element focus, and other editing events."]})}),"\n",(0,i.jsxs)(n.p,{children:["Invokes ",(0,i.jsx)(n.code,{children:"changeText"})," event handler on the element or parent element in the tree."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-jsx",children:"import { View, TextInput } from 'react-native';\nimport { render, screen, fireEvent } from '@testing-library/react-native';\n\nconst onChangeTextMock = jest.fn();\nconst CHANGE_TEXT = 'content';\n\nrender(\n \n \n \n);\n\nfireEvent.changeText(screen.getByPlaceholderText('Enter data'), CHANGE_TEXT);\n"})}),"\n",(0,i.jsx)(n.h3,{id:"fireeventscroll",children:(0,i.jsx)(n.code,{children:"fireEvent.scroll"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:"fireEvent.scroll: (element: ReactTestInstance, ...data: Array) => void\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Invokes ",(0,i.jsx)(n.code,{children:"scroll"})," event handler on the element or parent element in the tree."]}),"\n",(0,i.jsxs)(n.h4,{id:"on-a-scrollview",children:["On a ",(0,i.jsx)(n.code,{children:"ScrollView"})]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-jsx",children:"import { ScrollView, Text } from 'react-native';\nimport { render, screen, fireEvent } from '@testing-library/react-native';\n\nconst onScrollMock = jest.fn();\nconst eventData = {\n nativeEvent: {\n contentOffset: {\n y: 200,\n },\n },\n};\n\nrender(\n \n XD\n \n);\n\nfireEvent.scroll(screen.getByText('scroll-view'), eventData);\n"})}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsxs)(n.p,{children:["Prefer using ",(0,i.jsx)(n.a,{href:"/react-native-testing-library/docs/user-event#scrollto",children:(0,i.jsx)(n.code,{children:"user.scrollTo"})})," over ",(0,i.jsx)(n.code,{children:"fireEvent.scroll"})," for ",(0,i.jsx)(n.code,{children:"ScrollView"}),", ",(0,i.jsx)(n.code,{children:"FlatList"}),", and ",(0,i.jsx)(n.code,{children:"SectionList"})," components. User Event provides a more realistic event simulation based on React Native runtime behavior."]})}),"\n",(0,i.jsx)(n.h2,{id:"helper-functions",children:"Helper functions"}),"\n",(0,i.jsx)(n.h3,{id:"waitfor",children:(0,i.jsx)(n.code,{children:"waitFor"})}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"https://github.com/callstack/react-native-testing-library/blob/main/src/__tests__/wait-for.test.tsx",children:(0,i.jsx)(n.code,{children:"Example code"})})}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"Defined as:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-jsx",children:"function waitFor(\n expectation: () => T,\n { timeout: number = 1000, interval: number = 50 }\n): Promise {}\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Waits for a period of time for the ",(0,i.jsx)(n.code,{children:"expectation"})," callback to pass. ",(0,i.jsx)(n.code,{children:"waitFor"})," may run the callback a number of times until timeout is reached, as specified by the ",(0,i.jsx)(n.code,{children:"timeout"})," and ",(0,i.jsx)(n.code,{children:"interval"})," options. The callback must throw an error when the expectation is not met. Returning any value, including a falsy one, will be treated as meeting the expectation, and the callback result will be returned to the caller of ",(0,i.jsx)(n.code,{children:"waitFor"})," function."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-tsx",children:"await waitFor(() => expect(mockFunction).toHaveBeenCalledWith())\n"})}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.code,{children:"waitFor"})," function will be executing ",(0,i.jsx)(n.code,{children:"expectation"})," callback every ",(0,i.jsx)(n.code,{children:"interval"})," (default: every 50 ms) until ",(0,i.jsx)(n.code,{children:"timeout"})," (default: 1000 ms) is reached. The repeated execution of callback is stopped as soon as it does not throw an error, in such case the value returned by the callback is returned to ",(0,i.jsx)(n.code,{children:"waitFor"})," caller. Otherwise, when it reaches the timeout, the final error thrown by ",(0,i.jsx)(n.code,{children:"expectation"})," will be re-thrown by ",(0,i.jsx)(n.code,{children:"waitFor"})," to the calling code."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-tsx",children:"// \u274c `waitFor` will return immediately because callback does not throw\nawait waitFor(() => false);\n"})}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.code,{children:"waitFor"})," is an async function so you need to ",(0,i.jsx)(n.code,{children:"await"})," the result to pause test execution."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-jsx",children:"// \u274c missing `await`: `waitFor` will just return Promise that will be rejected when the timeout is reached\nwaitFor(() => expect(1).toBe(2));\n"})}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsxs)(n.p,{children:["You can enforce awaiting ",(0,i.jsx)(n.code,{children:"waitFor"})," by using the ",(0,i.jsx)(n.a,{href:"https://github.com/testing-library/eslint-plugin-testing-library/blob/main/docs/rules/await-async-utils.md",children:"await-async-utils"})," rule from ",(0,i.jsx)(n.a,{href:"https://github.com/testing-library/eslint-plugin-testing-library",children:"eslint-plugin-testing-library"}),"."]})}),"\n",(0,i.jsxs)(n.p,{children:["Since ",(0,i.jsx)(n.code,{children:"waitFor"})," is likely to run ",(0,i.jsx)(n.code,{children:"expectation"})," callback multiple times, it is highly recommended for it ",(0,i.jsx)(n.a,{href:"https://kentcdodds.com/blog/common-mistakes-with-react-testing-library#performing-side-effects-in-waitfor",children:"not to perform any side effects"})," in ",(0,i.jsx)(n.code,{children:"waitFor"}),"."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-jsx",children:"await waitFor(() => {\n // \u274c button will be pressed on each waitFor iteration\n fireEvent.press(screen.getByText('press me'));\n expect(mockOnPress).toHaveBeenCalled();\n});\n"})}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsxs)(n.p,{children:["Avoiding side effects in ",(0,i.jsx)(n.code,{children:"expectation"})," callback can be partially enforced with the ",(0,i.jsxs)(n.a,{href:"https://github.com/testing-library/eslint-plugin-testing-library/blob/main/docs/rules/no-wait-for-side-effects.md",children:[(0,i.jsx)(n.code,{children:"no-wait-for-side-effects"})," rule"]}),"."]})}),"\n",(0,i.jsxs)(n.p,{children:["It is also recommended to have a ",(0,i.jsxs)(n.a,{href:"https://kentcdodds.com/blog/common-mistakes-with-react-testing-library#having-multiple-assertions-in-a-single-waitfor-callback",children:["single assertion per each ",(0,i.jsx)(n.code,{children:"waitFor"})]})," for more consistency and faster failing tests. If you want to make several assertions, then they should be in seperate ",(0,i.jsx)(n.code,{children:"waitFor"})," calls. In many cases you won't actually need to wrap the second assertion in ",(0,i.jsx)(n.code,{children:"waitFor"})," since the first one will do the waiting required for asynchronous change to happen."]}),"\n",(0,i.jsx)(n.h4,{id:"using-a-react-native-version--071-with-jest-fake-timers",children:"Using a React Native version < 0.71 with Jest fake timers"}),"\n",(0,i.jsx)(n.admonition,{type:"caution",children:(0,i.jsxs)(n.p,{children:["When using a version of React Native < 0.71 and modern fake timers (the default for ",(0,i.jsx)(n.code,{children:"Jest"})," >= 27), ",(0,i.jsx)(n.code,{children:"waitFor"})," won't work (it will always timeout even if ",(0,i.jsx)(n.code,{children:"expectation()"})," doesn't throw) unless you use the custom ",(0,i.jsx)(n.a,{href:"https://github.com/callstack/react-native-testing-library#custom-jest-preset",children:"@testing-library/react-native preset"}),"."]})}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.code,{children:"waitFor"})," checks whether Jest fake timers are enabled and adapts its behavior in such case. The following snippet is a simplified version of how it behaves when fake timers are enabled:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-tsx",children:"let fakeTimeRemaining = timeout;\nlet lastError;\n\nwhile (fakeTimeRemaining > 0) {\n fakeTimeRemaining = fakeTimeRemaining - interval;\n jest.advanceTimersByTime(interval);\n try {\n // resolve\n return expectation();\n } catch (error) {\n lastError = error;\n }\n}\n\n// reject\nthrow lastError;\n"})}),"\n",(0,i.jsxs)(n.p,{children:["In the following example we test that a function is called after 10 seconds using fake timers. Since we're using fake timers, the test won't depend on real time passing and thus be much faster and more reliable. Also we don't have to advance fake timers through Jest fake timers API because ",(0,i.jsx)(n.code,{children:"waitFor"})," already does this for us."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-tsx",children:"// in component\nsetTimeout(() => {\n someFunction();\n}, 10000);\n\n// in test\njest.useFakeTimers();\n\nawait waitFor(() => {\n expect(someFunction).toHaveBeenCalledWith();\n}, 10000);\n"})}),"\n",(0,i.jsx)(n.admonition,{type:"info",children:(0,i.jsxs)(n.p,{children:["In order to properly use ",(0,i.jsx)(n.code,{children:"waitFor"})," you need at least React >=16.9.0 (featuring async ",(0,i.jsx)(n.code,{children:"act"}),") or React Native >=0.61 (which comes with React >=16.9.0)."]})}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsxs)(n.p,{children:["If you receive warnings related to ",(0,i.jsx)(n.code,{children:"act()"})," function consult our ",(0,i.jsx)(n.a,{href:"/react-native-testing-library/docs/understanding-act",children:"Undestanding Act"})," function document."]})}),"\n",(0,i.jsx)(n.h3,{id:"waitforelementtoberemoved",children:(0,i.jsx)(n.code,{children:"waitForElementToBeRemoved"})}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["[",(0,i.jsx)(n.code,{children:"Example code"}),"]",(0,i.jsx)(n.a,{href:"https://github.com/callstack/react-native-testing-library/blob/main/src/__tests__/wait-for-element-to-be-removed.test.tsx",children:"https://github.com/callstack/react-native-testing-library/blob/main/src/__tests__/wait-for-element-to-be-removed.test.tsx"}),")"]}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"Defined as:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"function waitForElementToBeRemoved(\n expectation: () => T,\n { timeout: number = 4500, interval: number = 50 }\n): Promise {}\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Waits for non-deterministic periods of time until queried element is removed or times out. ",(0,i.jsx)(n.code,{children:"waitForElementToBeRemoved"})," periodically calls ",(0,i.jsx)(n.code,{children:"expectation"})," every ",(0,i.jsx)(n.code,{children:"interval"})," milliseconds to determine whether the element has been removed or not."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-jsx",children:"import { render, screen, waitForElementToBeRemoved } from '@testing-library/react-native';\n\ntest('waiting for an Banana to be removed', async () => {\n render();\n\n await waitForElementToBeRemoved(() => screen.getByText('Banana ready'));\n});\n"})}),"\n",(0,i.jsx)(n.p,{children:"This method expects that the element is initially 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."}),"\n",(0,i.jsxs)(n.p,{children:["You can use any of ",(0,i.jsx)(n.code,{children:"getBy"}),", ",(0,i.jsx)(n.code,{children:"getAllBy"}),", ",(0,i.jsx)(n.code,{children:"queryBy"})," and ",(0,i.jsx)(n.code,{children:"queryAllBy"})," queries for ",(0,i.jsx)(n.code,{children:"expectation"})," parameter."]}),"\n",(0,i.jsx)(n.admonition,{type:"info",children:(0,i.jsxs)(n.p,{children:["In order to properly use ",(0,i.jsx)(n.code,{children:"waitForElementToBeRemoved"})," you need at least React >=16.9.0 (featuring async ",(0,i.jsx)(n.code,{children:"act"}),") or React Native >=0.61 (which comes with React >=16.9.0)."]})}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsxs)(n.p,{children:["If you receive warnings related to ",(0,i.jsx)(n.code,{children:"act()"})," function consult our ",(0,i.jsx)(n.a,{href:"/react-native-testing-library/docs/understanding-act",children:"Undestanding Act"})," function document."]})}),"\n",(0,i.jsxs)(n.h3,{id:"within-getqueriesforelement",children:[(0,i.jsx)(n.code,{children:"within"}),", ",(0,i.jsx)(n.code,{children:"getQueriesForElement"})]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:(0,i.jsx)(n.a,{href:"https://github.com/callstack/react-native-testing-library/blob/main/src/__tests__/within.test.tsx",children:(0,i.jsx)(n.code,{children:"Example code"})})}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"Defined as:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-jsx",children:"function within(element: ReactTestInstance): Queries {}\n\nfunction getQueriesForElement(element: ReactTestInstance): Queries {}\n"})}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.code,{children:"within"})," (also available as ",(0,i.jsx)(n.code,{children:"getQueriesForElement"})," alias) performs ",(0,i.jsx)(n.a,{href:"/react-native-testing-library/docs/api-queries",children:"queries"})," scoped to given element."]}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsxs)(n.p,{children:["Please note that additional ",(0,i.jsx)(n.code,{children:"render"})," specific operations like ",(0,i.jsx)(n.code,{children:"update"}),", ",(0,i.jsx)(n.code,{children:"unmount"}),", ",(0,i.jsx)(n.code,{children:"debug"}),", ",(0,i.jsx)(n.code,{children:"toJSON"})," are ",(0,i.jsx)(n.em,{children:"not"})," included."]})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-jsx",children:"const detailsScreen = within(screen.getByA11yHint('Details Screen'));\nexpect(detailsScreen.getByText('Some Text')).toBeOnTheScreen();\nexpect(detailsScreen.getByDisplayValue('Some Value')).toBeOnTheScreen();\nexpect(detailsScreen.queryByLabelText('Some Label')).toBeOnTheScreen();\nawait expect(detailsScreen.findByA11yHint('Some Label')).resolves.toBeOnTheScreen();\n"})}),"\n",(0,i.jsx)(n.p,{children:"Use cases for scoped queries include:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"queries scoped to a single item inside a FlatList containing many items"}),"\n",(0,i.jsx)(n.li,{children:"queries scoped to a single screen in tests involving screen transitions (e.g. with react-navigation)"}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"act",children:(0,i.jsx)(n.code,{children:"act"})}),"\n",(0,i.jsxs)(n.p,{children:["Useful function to help testing components that use hooks API. By default any ",(0,i.jsx)(n.code,{children:"render"}),", ",(0,i.jsx)(n.code,{children:"update"}),", ",(0,i.jsx)(n.code,{children:"fireEvent"}),", and ",(0,i.jsx)(n.code,{children:"waitFor"})," calls are wrapped by this function, so there is no need to wrap it manually. This method is re-exported from ",(0,i.jsx)(n.a,{href:"https://github.com/facebook/react/blob/main/packages/react-test-renderer/src/ReactTestRenderer.js#L567%5D",children:(0,i.jsx)(n.code,{children:"react-test-renderer"})}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["Consult our ",(0,i.jsx)(n.a,{href:"/react-native-testing-library/docs/understanding-act",children:"Undestanding Act function"})," document for more understanding of its intricacies."]}),"\n",(0,i.jsx)(n.h3,{id:"cleanup",children:(0,i.jsx)(n.code,{children:"cleanup"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"const cleanup: () => void;\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Unmounts React trees that were mounted with ",(0,i.jsx)(n.code,{children:"render"})," and clears ",(0,i.jsx)(n.code,{children:"screen"})," variable that holds latest ",(0,i.jsx)(n.code,{children:"render"})," output."]}),"\n",(0,i.jsx)(n.admonition,{type:"info",children:(0,i.jsxs)(n.p,{children:["Please note that this is done automatically if the testing framework you're using supports the ",(0,i.jsx)(n.code,{children:"afterEach"})," global (like mocha, Jest, and Jasmine). If not, you will need to do manual cleanups after each test."]})}),"\n",(0,i.jsxs)(n.p,{children:["For example, if you're using the ",(0,i.jsx)(n.code,{children:"jest"})," testing framework, then you would need to use the ",(0,i.jsx)(n.code,{children:"afterEach"})," hook like so:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-jsx",children:"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"})}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"afterEach(cleanup)"})," call also works in ",(0,i.jsx)(n.code,{children:"describe"})," blocks:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-jsx",children:"describe('when logged in', () => {\n afterEach(cleanup);\n\n it('renders the user', () => {\n render();\n // ...\n });\n});\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Failing to call ",(0,i.jsx)(n.code,{children:"cleanup"})," when you've called ",(0,i.jsx)(n.code,{children:"render"}),' could result in a memory leak and tests which are not "idempotent" (which can lead to difficult to debug errors in your tests).']}),"\n",(0,i.jsxs)(n.h2,{id:"renderhook-api",children:[(0,i.jsx)(n.code,{children:"renderHook"})," API"]}),"\n",(0,i.jsx)(n.p,{children:"Defined as:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"function renderHook(\n callback: (props?: Props) => Result,\n options?: RenderHookOptions\n): RenderHookResult;\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Renders a test component that will call the provided ",(0,i.jsx)(n.code,{children:"callback"}),", including any hooks it calls, every time it renders. Returns ",(0,i.jsx)(n.a,{href:"#renderhookresult-object",children:(0,i.jsx)(n.code,{children:"RenderHookResult"})})," object, which you can interact with."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"import { renderHook } from '@testing-library/react-native';\nimport { useCount } from '../useCount';\n\nit('should increment count', () => {\n const { result } = renderHook(() => useCount());\n\n expect(result.current.count).toBe(0);\n act(() => {\n // Note that you should wrap the calls to functions your hook returns with `act` if they trigger an update of your hook's state to ensure pending useEffects are run before your next assertion.\n result.current.increment();\n });\n expect(result.current.count).toBe(1);\n});\n"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"// useCount.js\nexport const useCount = () => {\n const [count, setCount] = useState(0);\n const increment = () => setCount((previousCount) => previousCount + 1);\n\n return { count, increment };\n};\n"})}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"renderHook"})," function accepts the following arguments:"]}),"\n",(0,i.jsxs)(n.p,{children:["Callback is a function that is called each ",(0,i.jsx)(n.code,{children:"render"})," of the test component. This function should call one or more hooks for testing."]}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"props"})," passed into the callback will be the ",(0,i.jsx)(n.code,{children:"initialProps"})," provided in the ",(0,i.jsx)(n.code,{children:"options"})," to ",(0,i.jsx)(n.code,{children:"renderHook"}),", unless new props are provided by a subsequent ",(0,i.jsx)(n.code,{children:"rerender"})," call."]}),"\n",(0,i.jsx)(n.h3,{id:"options",children:(0,i.jsx)(n.code,{children:"options"})}),"\n",(0,i.jsxs)(n.p,{children:["A ",(0,i.jsx)(n.code,{children:"RenderHookOptions"})," object to modify the execution of the ",(0,i.jsx)(n.code,{children:"callback"})," function, containing the following properties:"]}),"\n",(0,i.jsx)(n.h4,{id:"initialprops",children:(0,i.jsx)(n.code,{children:"initialProps"})}),"\n",(0,i.jsxs)(n.p,{children:["The initial values to pass as ",(0,i.jsx)(n.code,{children:"props"})," to the ",(0,i.jsx)(n.code,{children:"callback"})," function of ",(0,i.jsx)(n.code,{children:"renderHook"}),". The ",(0,i.jsx)(n.code,{children:"Props"})," type is determined by the type passed to or inferred by the ",(0,i.jsx)(n.code,{children:"renderHook"})," call."]}),"\n",(0,i.jsx)(n.h4,{id:"wrapper",children:(0,i.jsx)(n.code,{children:"wrapper"})}),"\n",(0,i.jsxs)(n.p,{children:["A React component to wrap the test component in when rendering. This is usually used to add context providers from ",(0,i.jsx)(n.code,{children:"React.createContext"})," for the hook to access with ",(0,i.jsx)(n.code,{children:"useContext"}),"."]}),"\n",(0,i.jsx)(n.h3,{id:"renderhookresult",children:(0,i.jsx)(n.code,{children:"RenderHookResult"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"interface RenderHookResult {\n result: { current: Result };\n rerender: (props: Props) => void;\n unmount: () => void;\n}\n"})}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"renderHook"})," function returns an object that has the following properties:"]}),"\n",(0,i.jsx)(n.h3,{id:"result",children:(0,i.jsx)(n.code,{children:"result"})}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"current"})," value of the ",(0,i.jsx)(n.code,{children:"result"})," will reflect the latest of whatever is returned from the ",(0,i.jsx)(n.code,{children:"callback"})," passed to ",(0,i.jsx)(n.code,{children:"renderHook"}),". The ",(0,i.jsx)(n.code,{children:"Result"})," type is determined by the type passed to or inferred by the ",(0,i.jsx)(n.code,{children:"renderHook"})," call."]}),"\n",(0,i.jsx)(n.h3,{id:"rerender",children:(0,i.jsx)(n.code,{children:"rerender"})}),"\n",(0,i.jsxs)(n.p,{children:["A function to rerender the test component, causing any hooks to be recalculated. If ",(0,i.jsx)(n.code,{children:"newProps"})," are passed, they will replace the ",(0,i.jsx)(n.code,{children:"callback"})," function's ",(0,i.jsx)(n.code,{children:"initialProps"})," for subsequent rerenders. The ",(0,i.jsx)(n.code,{children:"Props"})," type is determined by the type passed to or inferred by the ",(0,i.jsx)(n.code,{children:"renderHook"})," call."]}),"\n",(0,i.jsx)(n.h3,{id:"unmount-1",children:(0,i.jsx)(n.code,{children:"unmount"})}),"\n",(0,i.jsxs)(n.p,{children:["A function to unmount the test component. This is commonly used to trigger cleanup effects for ",(0,i.jsx)(n.code,{children:"useEffect"})," hooks."]}),"\n",(0,i.jsx)(n.h3,{id:"examples",children:"Examples"}),"\n",(0,i.jsxs)(n.p,{children:["Here we present some extra examples of using ",(0,i.jsx)(n.code,{children:"renderHook"})," API."]}),"\n",(0,i.jsxs)(n.h4,{id:"with-initialprops",children:["With ",(0,i.jsx)(n.code,{children:"initialProps"})]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"const useCount = (initialCount: number) => {\n const [count, setCount] = useState(initialCount);\n const increment = () => setCount((previousCount) => previousCount + 1);\n\n useEffect(() => {\n setCount(initialCount);\n }, [initialCount]);\n\n return { count, increment };\n};\n\nit('should increment count', () => {\n const { result, rerender } = renderHook((initialCount: number) => useCount(initialCount), {\n initialProps: 1,\n });\n\n expect(result.current.count).toBe(1);\n\n act(() => {\n result.current.increment();\n });\n\n expect(result.current.count).toBe(2);\n rerender(5);\n expect(result.current.count).toBe(5);\n});\n"})}),"\n",(0,i.jsxs)(n.h4,{id:"with-wrapper",children:["With ",(0,i.jsx)(n.code,{children:"wrapper"})]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-tsx",children:"it('should use context value', () => {\n function Wrapper({ children }: { children: ReactNode }) {\n return {children};\n }\n\n const { result } = renderHook(() => useHook(), { wrapper: Wrapper });\n // ...\n});\n"})}),"\n",(0,i.jsx)(n.h2,{id:"configuration",children:"Configuration"}),"\n",(0,i.jsx)(n.h3,{id:"configure",children:(0,i.jsx)(n.code,{children:"configure"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"type Config = {\n asyncUtilTimeout: number;\n defaultHidden: boolean;\n defaultDebugOptions: Partial;\n};\n\nfunction configure(options: Partial) {}\n"})}),"\n",(0,i.jsxs)(n.h4,{id:"asyncutiltimeout-option",children:[(0,i.jsx)(n.code,{children:"asyncUtilTimeout"})," option"]}),"\n",(0,i.jsxs)(n.p,{children:["Default timeout, in ms, for async helper functions (",(0,i.jsx)(n.code,{children:"waitFor"}),", ",(0,i.jsx)(n.code,{children:"waitForElementToBeRemoved"}),") and ",(0,i.jsx)(n.code,{children:"findBy*"})," queries. Defaults to 1000 ms."]}),"\n",(0,i.jsxs)(n.h4,{id:"defaultincludehiddenelements-option",children:[(0,i.jsx)(n.code,{children:"defaultIncludeHiddenElements"})," option"]}),"\n",(0,i.jsxs)(n.p,{children:["Default value for ",(0,i.jsx)(n.a,{href:"/react-native-testing-library/docs/api-queries#includehiddenelements-option",children:"includeHiddenElements"})," query option for all queries. The default value is set to ",(0,i.jsx)(n.code,{children:"false"}),", so all queries will not match ",(0,i.jsx)(n.a,{href:"#ishiddenfromaccessibility",children:"elements hidden from accessibility"}),". This is because the users of the app would not be able to see such elements."]}),"\n",(0,i.jsxs)(n.p,{children:["This option is also available as ",(0,i.jsx)(n.code,{children:"defaultHidden"})," alias for compatibility with ",(0,i.jsx)(n.a,{href:"https://testing-library.com/docs/dom-testing-library/api-configuration/#defaulthidden",children:"React Testing Library"}),"."]}),"\n",(0,i.jsxs)(n.h4,{id:"defaultdebugoptions-option",children:[(0,i.jsx)(n.code,{children:"defaultDebugOptions"})," option"]}),"\n",(0,i.jsxs)(n.p,{children:["Default ",(0,i.jsx)(n.a,{href:"#debug",children:"debug options"})," to be used when calling ",(0,i.jsx)(n.code,{children:"debug()"}),". These default options will be overridden by the ones you specify directly when calling ",(0,i.jsx)(n.code,{children:"debug()"}),"."]}),"\n",(0,i.jsx)(n.h3,{id:"resettodefaults",children:(0,i.jsx)(n.code,{children:"resetToDefaults()"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"function resetToDefaults() {}\n"})}),"\n",(0,i.jsx)(n.h3,{id:"environment-variables",children:"Environment variables"}),"\n",(0,i.jsx)(n.h4,{id:"rntl_skip_auto_cleanup",children:(0,i.jsx)(n.code,{children:"RNTL_SKIP_AUTO_CLEANUP"})}),"\n",(0,i.jsxs)(n.p,{children:["Set to ",(0,i.jsx)(n.code,{children:"true"})," to disable automatic ",(0,i.jsx)(n.code,{children:"cleanup()"})," after each test. It works the same as importing ",(0,i.jsx)(n.code,{children:"react-native-testing-library/dont-cleanup-after-each"})," or using ",(0,i.jsx)(n.code,{children:"react-native-testing-library/pure"}),"."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-shell",children:"$ RNTL_SKIP_AUTO_CLEANUP=true jest\n"})}),"\n",(0,i.jsx)(n.h4,{id:"rntl_skip_auto_detect_fake_timers",children:(0,i.jsx)(n.code,{children:"RNTL_SKIP_AUTO_DETECT_FAKE_TIMERS"})}),"\n",(0,i.jsxs)(n.p,{children:["Set to ",(0,i.jsx)(n.code,{children:"true"})," to disable auto-detection of fake timers. This might be useful in rare cases when you want to use non-Jest fake timers. See ",(0,i.jsx)(n.a,{href:"https://github.com/callstack/react-native-testing-library/issues/886",children:"issue #886"})," for more details."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-shell",children:"$ RNTL_SKIP_AUTO_DETECT_FAKE_TIMERS=true jest\n"})}),"\n",(0,i.jsx)(n.h2,{id:"accessibility",children:"Accessibility"}),"\n",(0,i.jsx)(n.h3,{id:"ishiddenfromaccessibility",children:(0,i.jsx)(n.code,{children:"isHiddenFromAccessibility"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-ts",children:"function isHiddenFromAccessibility(\n element: ReactTestInstance | null\n): boolean {}\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Also available as ",(0,i.jsx)(n.code,{children:"isInaccessible()"})," alias for React Testing Library compatibility."]}),"\n",(0,i.jsx)(n.p,{children:"Checks if given element is hidden from assistive technology, e.g. screen readers."}),"\n",(0,i.jsxs)(n.admonition,{type:"note",children:[(0,i.jsxs)(n.p,{children:["Like ",(0,i.jsx)(n.a,{href:"https://testing-library.com/docs/dom-testing-library/api-accessibility/#isinaccessible",children:(0,i.jsx)(n.code,{children:"isInaccessible"})})," function from DOM Testing Library this function considers both accessibility elements and presentational elements (regular ",(0,i.jsx)(n.code,{children:"View"}),"s) to be accessible, unless they are hidden in terms of host platform."]}),(0,i.jsxs)(n.p,{children:["This covers only part of ",(0,i.jsx)(n.a,{href:"https://www.w3.org/TR/wai-aria-1.2/#tree_exclusion",children:"ARIA notion of Accessiblity Tree"}),", as ARIA excludes both hidden and presentational elements from the Accessibility Tree."]})]}),"\n",(0,i.jsx)(n.p,{children:"For the scope of this function, element is inaccessible when it, or any of its ancestors, meets any of the following conditions:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["it has ",(0,i.jsx)(n.code,{children:"display: none"})," style"]}),"\n",(0,i.jsxs)(n.li,{children:["it has ",(0,i.jsx)(n.a,{href:"https://reactnative.dev/docs/accessibility#aria-hidden",children:(0,i.jsx)(n.code,{children:"aria-hidden"})})," prop set to ",(0,i.jsx)(n.code,{children:"true"})]}),"\n",(0,i.jsxs)(n.li,{children:["it has ",(0,i.jsx)(n.a,{href:"https://reactnative.dev/docs/accessibility#accessibilityelementshidden-ios",children:(0,i.jsx)(n.code,{children:"accessibilityElementsHidden"})})," prop set to ",(0,i.jsx)(n.code,{children:"true"})]}),"\n",(0,i.jsxs)(n.li,{children:["it has ",(0,i.jsx)(n.a,{href:"https://reactnative.dev/docs/accessibility#importantforaccessibility-android",children:(0,i.jsx)(n.code,{children:"importantForAccessibility"})})," prop set to ",(0,i.jsx)(n.code,{children:"no-hide-descendants"})]}),"\n",(0,i.jsxs)(n.li,{children:["it has sibling host element with either ",(0,i.jsx)(n.a,{href:"https://reactnative.dev/docs/accessibility#aria-modal-ios",children:(0,i.jsx)(n.code,{children:"aria-modal"})})," or ",(0,i.jsx)(n.a,{href:"https://reactnative.dev/docs/accessibility#accessibilityviewismodal-ios",children:(0,i.jsx)(n.code,{children:"accessibilityViewIsModal"})})," prop set to ",(0,i.jsx)(n.code,{children:"true"})]}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["Specifying ",(0,i.jsx)(n.code,{children:"accessible={false}"}),", ",(0,i.jsx)(n.code,{children:'accessiblityRole="none"'}),", or ",(0,i.jsx)(n.code,{children:'importantForAccessibility="no"'})," props does not cause the element to become inaccessible."]})]})}function u(e={}){const{wrapper:n}={...(0,s.a)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(h,{...e})}):h(e)}},1151:(e,n,t)=>{t.d(n,{Z:()=>c,a:()=>o});var i=t(7294);const s={},r=i.createContext(s);function o(e){const n=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function c(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:o(e.components),i.createElement(r.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/d77361a5.9a82e889.js b/assets/js/d77361a5.9a82e889.js deleted file mode 100644 index 69e58158..00000000 --- a/assets/js/d77361a5.9a82e889.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkreact_native_testing_library_website=self.webpackChunkreact_native_testing_library_website||[]).push([[884],{6062:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>m,frontMatter:()=>r,metadata:()=>o,toc:()=>l});var i=n(5893),s=n(1151);const r={id:"community-resources",title:"Community Resources"},a=void 0,o={id:"community-resources",title:"Community Resources",description:"Recommended content",source:"@site/docs/CommunityResources.md",sourceDirName:".",slug:"/community-resources",permalink:"/react-native-testing-library/docs/community-resources",draft:!1,unlisted:!1,editUrl:"https://github.com/callstack/react-native-testing-library/blob/main/website/docs/CommunityResources.md",tags:[],version:"current",frontMatter:{id:"community-resources",title:"Community Resources"},sidebar:"docs",previous:{title:"Understanding Act function",permalink:"/react-native-testing-library/docs/understanding-act"},next:{title:"Migration from Jest Native matchers",permalink:"/react-native-testing-library/docs/migration-jest-native"}},c={},l=[{value:"Recommended content",id:"recommended-content",level:3},{value:"Older, potentially outdated content",id:"older-potentially-outdated-content",level:3}];function d(e){const t={a:"a",h3:"h3",li:"li",ul:"ul",...(0,s.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(t.h3,{id:"recommended-content",children:"Recommended content"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.a,{href:"https://kentcdodds.com/blog/the-testing-trophy-and-testing-classifications",children:"The Testing Trophy and Testing Classifications"})," by Kent C. Dodds (2021) - classic article explaining testing philosophy behind all Testing Library implementations."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.a,{href:"https://kentcdodds.com/blog/common-mistakes-with-react-testing-library",children:"Common mistakes with React Testing Library"})," by Kent C. Dodds (2020) - classic article explaining React Testing Library best practices, highly applicable to RNTL as well."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.a,{href:"https://github.com/anisurrahman072/React-Native-Advanced-Guide/blob/master/Testing/RNTL-Component-Testing-ultimate-guide.md",children:"React Native \u2014 UI Testing (Ultimate Guide)"})," by Anisur Rahman - comprehensive guide to RNTL testing"]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.a,{href:"https://github.com/vanGalilea/react-native-testing",children:"React Native Testing examples repo"})," by Steve Galili - extensive repo with RN testing examples for RNTL and Maestro"]}),"\n"]}),"\n",(0,i.jsx)(t.h3,{id:"older-potentially-outdated-content",children:"Older, potentially outdated content"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.a,{href:"https://blog.usejournal.com/where-and-how-to-start-testing-your-react-native-app-%EF%B8%8F-and-how-to-keep-on-testin-ec3464fb9b41",children:"Where and how to start testing \ud83e\uddea your react-native app \u269b\ufe0f and how to keep on testin\u2019"})," by Steve Galili (2020) - article referencing Steve's examples repo."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.a,{href:"https://youtu.be/CpTQb0XWlRc",children:"Intro to React Native Testing Library & Jest Native"})," by Alireza Ghamkhar (2020) - video tutorial on RNTL setup and testing."]}),"\n"]})]})}function m(e={}){const{wrapper:t}={...(0,s.a)(),...e.components};return t?(0,i.jsx)(t,{...e,children:(0,i.jsx)(d,{...e})}):d(e)}},1151:(e,t,n)=>{n.d(t,{Z:()=>o,a:()=>a});var i=n(7294);const s={},r=i.createContext(s);function a(e){const t=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:a(e.components),i.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/d77361a5.ebc4b2b7.js b/assets/js/d77361a5.ebc4b2b7.js new file mode 100644 index 00000000..4f915e49 --- /dev/null +++ b/assets/js/d77361a5.ebc4b2b7.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkreact_native_testing_library_website=self.webpackChunkreact_native_testing_library_website||[]).push([[884],{6062:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>m,frontMatter:()=>r,metadata:()=>o,toc:()=>l});var i=n(5893),s=n(1151);const r={id:"community-resources",title:"Community Resources"},a=void 0,o={id:"community-resources",title:"Community Resources",description:"Recommended content",source:"@site/docs/CommunityResources.md",sourceDirName:".",slug:"/community-resources",permalink:"/react-native-testing-library/docs/community-resources",draft:!1,unlisted:!1,editUrl:"https://github.com/callstack/react-native-testing-library/blob/main/website/docs/CommunityResources.md",tags:[],version:"current",frontMatter:{id:"community-resources",title:"Community Resources"},sidebar:"docs",previous:{title:"Understanding Act function",permalink:"/react-native-testing-library/docs/understanding-act"},next:{title:"Migration from Jest Native matchers",permalink:"/react-native-testing-library/docs/migration-jest-native"}},c={},l=[{value:"Recommended content",id:"recommended-content",level:3},{value:"Older, potentially outdated content",id:"older-potentially-outdated-content",level:3}];function d(e){const t={a:"a",h3:"h3",li:"li",ul:"ul",...(0,s.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(t.h3,{id:"recommended-content",children:"Recommended content"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.a,{href:"https://kentcdodds.com/blog/the-testing-trophy-and-testing-classifications",children:"The Testing Trophy and Testing Classifications"})," by Kent C. Dodds (2021) - classic article explaining testing philosophy behind all Testing Library implementations."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.a,{href:"https://kentcdodds.com/blog/common-mistakes-with-react-testing-library",children:"Common mistakes with React Testing Library"})," by Kent C. Dodds (2020) - classic article explaining React Testing Library best practices, highly applicable to RNTL as well."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.a,{href:"https://github.com/anisurrahman072/React-Native-Advanced-Guide/blob/master/Testing/RNTL-Component-Testing-ultimate-guide.md",children:"React Native \u2014 UI Testing (Ultimate Guide)"})," by Anisur Rahman - comprehensive guide to RNTL testing"]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.a,{href:"https://github.com/vanGalilea/react-native-testing",children:"React Native Testing examples repo"})," by Steve Galili - extensive repo with RN testing examples for RNTL and Maestro"]}),"\n"]}),"\n",(0,i.jsx)(t.h3,{id:"older-potentially-outdated-content",children:"Older, potentially outdated content"}),"\n",(0,i.jsxs)(t.ul,{children:["\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.a,{href:"https://blog.usejournal.com/where-and-how-to-start-testing-your-react-native-app-%EF%B8%8F-and-how-to-keep-on-testin-ec3464fb9b41",children:"Where and how to start testing \ud83e\uddea your react-native app \u269b\ufe0f and how to keep on testin\u2019"})," by Steve Galili (2020) - article referencing Steve's examples repo."]}),"\n",(0,i.jsxs)(t.li,{children:[(0,i.jsx)(t.a,{href:"https://youtu.be/CpTQb0XWlRc",children:"Intro to React Native Testing Library & Jest Native"})," by Alireza Ghamkhar (2020) - video tutorial on RNTL setup and testing."]}),"\n"]})]})}function m(e={}){const{wrapper:t}={...(0,s.a)(),...e.components};return t?(0,i.jsx)(t,{...e,children:(0,i.jsx)(d,{...e})}):d(e)}},1151:(e,t,n)=>{n.d(t,{Z:()=>o,a:()=>a});var i=n(7294);const s={},r=i.createContext(s);function a(e){const t=i.useContext(r);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:a(e.components),i.createElement(r.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/f69ec364.e1bd5bf9.js b/assets/js/f69ec364.1556e56b.js similarity index 79% rename from assets/js/f69ec364.e1bd5bf9.js rename to assets/js/f69ec364.1556e56b.js index 8d1553b4..95b06456 100644 --- a/assets/js/f69ec364.e1bd5bf9.js +++ b/assets/js/f69ec364.1556e56b.js @@ -1 +1 @@ -"use strict";(self.webpackChunkreact_native_testing_library_website=self.webpackChunkreact_native_testing_library_website||[]).push([[690],{2063:(e,t,n)=>{n.d(t,{Z:()=>s});n(7294);var i=n(1351);const r={tableOfContentsInline:"tableOfContentsInline_prmo"};var a=n(5893);function s(e){let{toc:t,minHeadingLevel:n,maxHeadingLevel:s}=e;return(0,a.jsx)("div",{className:r.tableOfContentsInline,children:(0,a.jsx)(i.Z,{toc:t,minHeadingLevel:n,maxHeadingLevel:s,className:"table-of-contents",linkClassName:null})})}},1351:(e,t,n)=>{n.d(t,{Z:()=>f});var i=n(7294),r=n(6793);function a(e){const t=e.map((e=>({...e,parentIndex:-1,children:[]}))),n=Array(7).fill(-1);t.forEach(((e,t)=>{const i=n.slice(2,e.level);e.parentIndex=Math.max(...i),n[e.level]=t}));const i=[];return t.forEach((e=>{const{parentIndex:n,...r}=e;n>=0?t[n].children.push(r):i.push(r)})),i}function s(e){let{toc:t,minHeadingLevel:n,maxHeadingLevel:i}=e;return t.flatMap((e=>{const t=s({toc:e.children,minHeadingLevel:n,maxHeadingLevel:i});return function(e){return e.level>=n&&e.level<=i}(e)?[{...e,children:t}]:t}))}function o(e){const t=e.getBoundingClientRect();return t.top===t.bottom?o(e.parentNode):t}function l(e,t){var n;let{anchorTopOffset:i}=t;const r=e.find((e=>o(e).top>=i));if(r){var a;return function(e){return e.top>0&&e.bottom{e.current=t?0:document.querySelector(".navbar").clientHeight}),[t]),e}function d(e){const t=(0,i.useRef)(void 0),n=c();(0,i.useEffect)((()=>{if(!e)return()=>{};const{linkClassName:i,linkActiveClassName:r,minHeadingLevel:a,maxHeadingLevel:s}=e;function o(){const e=function(e){return Array.from(document.getElementsByClassName(e))}(i),o=function(e){let{minHeadingLevel:t,maxHeadingLevel:n}=e;const i=[];for(let r=t;r<=n;r+=1)i.push("h"+r+".anchor");return Array.from(document.querySelectorAll(i.join()))}({minHeadingLevel:a,maxHeadingLevel:s}),c=l(o,{anchorTopOffset:n.current}),d=e.find((e=>c&&c.id===function(e){return decodeURIComponent(e.href.substring(e.href.indexOf("#")+1))}(e)));e.forEach((e=>{!function(e,n){n?(t.current&&t.current!==e&&t.current.classList.remove(r),e.classList.add(r),t.current=e):e.classList.remove(r)}(e,e===d)}))}return document.addEventListener("scroll",o),document.addEventListener("resize",o),o(),()=>{document.removeEventListener("scroll",o),document.removeEventListener("resize",o)}}),[e,n])}var u=n(8746),h=n(5893);function m(e){let{toc:t,className:n,linkClassName:i,isChild:r}=e;return t.length?(0,h.jsx)("ul",{className:r?void 0:n,children:t.map((e=>(0,h.jsxs)("li",{children:[(0,h.jsx)(u.Z,{to:"#"+e.id,className:null!=i?i:void 0,dangerouslySetInnerHTML:{__html:e.value}}),(0,h.jsx)(m,{isChild:!0,toc:e.children,className:n,linkClassName:i})]},e.id)))}):null}const g=i.memo(m);function f(e){let{toc:t,className:n="table-of-contents table-of-contents__left-border",linkClassName:o="table-of-contents__link",linkActiveClassName:l,minHeadingLevel:c,maxHeadingLevel:u,...m}=e;const f=(0,r.L)(),p=null!=c?c:f.tableOfContents.minHeadingLevel,v=null!=u?u:f.tableOfContents.maxHeadingLevel,x=function(e){let{toc:t,minHeadingLevel:n,maxHeadingLevel:r}=e;return(0,i.useMemo)((()=>s({toc:a(t),minHeadingLevel:n,maxHeadingLevel:r})),[t,n,r])}({toc:t,minHeadingLevel:p,maxHeadingLevel:v});return d((0,i.useMemo)((()=>{if(o&&l)return{linkClassName:o,linkActiveClassName:l,minHeadingLevel:p,maxHeadingLevel:v}}),[o,l,p,v])),(0,h.jsx)(g,{toc:x,className:n,linkClassName:o,...m})}},5566:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>h,frontMatter:()=>s,metadata:()=>l,toc:()=>d});var i=n(5893),r=n(1151),a=n(2063);const s={id:"migration-v9",title:"Migration to 9.0"},o=void 0,l={id:"migration-v9",title:"Migration to 9.0",description:"Version 7.0 brought React Native Testing Library into the @testing-library family. Since it has been implemented independently from its web counterpart \u2013 the React Testing Library \u2013 there are some differences in the API and behavior. Version 9.0 solves several of these problems.",source:"@site/docs/MigrationV9.md",sourceDirName:".",slug:"/migration-v9",permalink:"/react-native-testing-library/docs/migration-v9",draft:!1,unlisted:!1,editUrl:"https://github.com/callstack/react-native-testing-library/blob/main/website/docs/MigrationV9.md",tags:[],version:"current",frontMatter:{id:"migration-v9",title:"Migration to 9.0"},sidebar:"docs",previous:{title:"Migration to 11.0",permalink:"/react-native-testing-library/docs/migration-v11"},next:{title:"Migration to 7.0",permalink:"/react-native-testing-library/docs/migration-v7"}},c={},d=[{value:"Support for text match options a.k.a string precision API",id:"support-for-text-match-options-aka-string-precision-api",level:2},{value:"Reverted matching text across several nodes",id:"reverted-matching-text-across-several-nodes",level:2},{value:"Future plans",id:"future-plans",level:2}];function u(e){const t={a:"a",admonition:"admonition",code:"code",h2:"h2",p:"p",pre:"pre",...(0,r.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsxs)(t.p,{children:["Version 7.0 brought React Native Testing Library into the ",(0,i.jsx)(t.code,{children:"@testing-library"})," family. Since it has been implemented independently from its web counterpart \u2013 the React Testing Library \u2013 there are some differences in the API and behavior. Version 9.0 solves several of these problems."]}),"\n",(0,i.jsx)(a.Z,{toc:d}),"\n",(0,i.jsx)(t.h2,{id:"support-for-text-match-options-aka-string-precision-api",children:"Support for text match options a.k.a string precision API"}),"\n",(0,i.jsx)(t.p,{children:"This is a backward compatible change."}),"\n",(0,i.jsxs)(t.p,{children:["When querying text, it is now possible to pass a ",(0,i.jsx)(t.a,{href:"https://callstack.github.io/react-native-testing-library/docs/api-queries/#textmatch",children:(0,i.jsx)(t.code,{children:"TextMatch"})})," to most text based queries, which lets you configure how ",(0,i.jsx)(t.code,{children:"@testing-library/react-native"})," should match your text. For instance, passing ",(0,i.jsx)(t.code,{children:"exact: false"})," will allow matching substrings and will ignore case:"]}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-jsx",children:"const { getByText } = render(Hello World);\n\ngetByText('Hello World'); // Matches\ngetByText('Hello'); // Doesn't match\ngetByText('hello', { exact: false }); // ignore case-sensitivity and does partial matching\n"})}),"\n",(0,i.jsxs)(t.p,{children:["Please note that the ",(0,i.jsx)(t.code,{children:"findBy*"})," queries used to take a ",(0,i.jsx)(t.code,{children:"waitForOptions"})," parameter as a second argument, which has now been moved to the third argument:"]}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-diff",children:"-findByText('Hello world', { timeout: 3000 }); // old findBy* API\n+findByText('Hello world', {}, { timeout: 3000 }); // new findBy* API\n"})}),"\n",(0,i.jsxs)(t.p,{children:["For backward compatibility RNTL v9 can still read ",(0,i.jsx)(t.code,{children:"waitForOptions"})," from the second argument but will print a deprecation warning."]}),"\n",(0,i.jsx)(t.h2,{id:"reverted-matching-text-across-several-nodes",children:"Reverted matching text across several nodes"}),"\n",(0,i.jsx)(t.admonition,{type:"caution",children:(0,i.jsx)(t.p,{children:"This is a breaking change."})}),"\n",(0,i.jsx)(t.p,{children:"In v1.14 we've introduced a feature allowing to match text when it's spread across several nodes:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-tsx",children:"const { getByText } = render(\n \n Hello world\n \n);\ngetByText('Hello world'); // matches\n"})}),"\n",(0,i.jsx)(t.p,{children:"However this behavior was different than the web one, and wouldn't always be straightforward to reason about. For instance it could match text nodes far from each other on the screen. It also prevented us from implementing the string precision API. From v9, this type of match will not work."}),"\n",(0,i.jsxs)(t.p,{children:["A work around is to use ",(0,i.jsx)(t.code,{children:"within"}),":"]}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-tsx",children:"import {Text} from 'react-native'\nimport {render, within} from '@testing-library/react-native'\n\nconst {getByText} = render(Hello world)\n\nwithin(getByText('Hello', {exact: false})).getByText('world')\n"})}),"\n",(0,i.jsx)(t.h2,{id:"future-plans",children:"Future plans"}),"\n",(0,i.jsx)(t.p,{children:"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."}),"\n",(0,i.jsxs)(t.p,{children:["We're also ",(0,i.jsx)(t.a,{href:"https://github.com/callstack/react-native-testing-library/issues/877",children:"migrating the codebase to TypeScript"}),". Please let us know if you're interested in helping us with this effort."]}),"\n",(0,i.jsx)(t.p,{children:"Stay safe!"})]})}function h(e={}){const{wrapper:t}={...(0,r.a)(),...e.components};return t?(0,i.jsx)(t,{...e,children:(0,i.jsx)(u,{...e})}):u(e)}},1151:(e,t,n)=>{n.d(t,{Z:()=>o,a:()=>s});var i=n(7294);const r={},a=i.createContext(r);function s(e){const t=i.useContext(a);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:s(e.components),i.createElement(a.Provider,{value:t},e.children)}}}]); \ No newline at end of file +"use strict";(self.webpackChunkreact_native_testing_library_website=self.webpackChunkreact_native_testing_library_website||[]).push([[690],{2063:(e,t,n)=>{n.d(t,{Z:()=>s});n(7294);var i=n(1351);const r={tableOfContentsInline:"tableOfContentsInline_prmo"};var a=n(5893);function s(e){let{toc:t,minHeadingLevel:n,maxHeadingLevel:s}=e;return(0,a.jsx)("div",{className:r.tableOfContentsInline,children:(0,a.jsx)(i.Z,{toc:t,minHeadingLevel:n,maxHeadingLevel:s,className:"table-of-contents",linkClassName:null})})}},1351:(e,t,n)=>{n.d(t,{Z:()=>f});var i=n(7294),r=n(6793);function a(e){const t=e.map((e=>({...e,parentIndex:-1,children:[]}))),n=Array(7).fill(-1);t.forEach(((e,t)=>{const i=n.slice(2,e.level);e.parentIndex=Math.max(...i),n[e.level]=t}));const i=[];return t.forEach((e=>{const{parentIndex:n,...r}=e;n>=0?t[n].children.push(r):i.push(r)})),i}function s(e){let{toc:t,minHeadingLevel:n,maxHeadingLevel:i}=e;return t.flatMap((e=>{const t=s({toc:e.children,minHeadingLevel:n,maxHeadingLevel:i});return function(e){return e.level>=n&&e.level<=i}(e)?[{...e,children:t}]:t}))}function o(e){const t=e.getBoundingClientRect();return t.top===t.bottom?o(e.parentNode):t}function l(e,t){var n;let{anchorTopOffset:i}=t;const r=e.find((e=>o(e).top>=i));if(r){var a;return function(e){return e.top>0&&e.bottom{e.current=t?0:document.querySelector(".navbar").clientHeight}),[t]),e}function d(e){const t=(0,i.useRef)(void 0),n=c();(0,i.useEffect)((()=>{if(!e)return()=>{};const{linkClassName:i,linkActiveClassName:r,minHeadingLevel:a,maxHeadingLevel:s}=e;function o(){const e=function(e){return Array.from(document.getElementsByClassName(e))}(i),o=function(e){let{minHeadingLevel:t,maxHeadingLevel:n}=e;const i=[];for(let r=t;r<=n;r+=1)i.push("h"+r+".anchor");return Array.from(document.querySelectorAll(i.join()))}({minHeadingLevel:a,maxHeadingLevel:s}),c=l(o,{anchorTopOffset:n.current}),d=e.find((e=>c&&c.id===function(e){return decodeURIComponent(e.href.substring(e.href.indexOf("#")+1))}(e)));e.forEach((e=>{!function(e,n){n?(t.current&&t.current!==e&&t.current.classList.remove(r),e.classList.add(r),t.current=e):e.classList.remove(r)}(e,e===d)}))}return document.addEventListener("scroll",o),document.addEventListener("resize",o),o(),()=>{document.removeEventListener("scroll",o),document.removeEventListener("resize",o)}}),[e,n])}var u=n(8746),h=n(5893);function m(e){let{toc:t,className:n,linkClassName:i,isChild:r}=e;return t.length?(0,h.jsx)("ul",{className:r?void 0:n,children:t.map((e=>(0,h.jsxs)("li",{children:[(0,h.jsx)(u.Z,{to:"#"+e.id,className:null!=i?i:void 0,dangerouslySetInnerHTML:{__html:e.value}}),(0,h.jsx)(m,{isChild:!0,toc:e.children,className:n,linkClassName:i})]},e.id)))}):null}const g=i.memo(m);function f(e){let{toc:t,className:n="table-of-contents table-of-contents__left-border",linkClassName:o="table-of-contents__link",linkActiveClassName:l,minHeadingLevel:c,maxHeadingLevel:u,...m}=e;const f=(0,r.L)(),p=null!=c?c:f.tableOfContents.minHeadingLevel,v=null!=u?u:f.tableOfContents.maxHeadingLevel,x=function(e){let{toc:t,minHeadingLevel:n,maxHeadingLevel:r}=e;return(0,i.useMemo)((()=>s({toc:a(t),minHeadingLevel:n,maxHeadingLevel:r})),[t,n,r])}({toc:t,minHeadingLevel:p,maxHeadingLevel:v});return d((0,i.useMemo)((()=>{if(o&&l)return{linkClassName:o,linkActiveClassName:l,minHeadingLevel:p,maxHeadingLevel:v}}),[o,l,p,v])),(0,h.jsx)(g,{toc:x,className:n,linkClassName:o,...m})}},5566:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>h,frontMatter:()=>s,metadata:()=>l,toc:()=>d});var i=n(5893),r=n(1151),a=n(2063);const s={id:"migration-v9",title:"Migration to 9.0"},o=void 0,l={id:"migration-v9",title:"Migration to 9.0",description:"Version 7.0 brought React Native Testing Library into the @testing-library family. Since it has been implemented independently from its web counterpart \u2013 the React Testing Library \u2013 there are some differences in the API and behavior. Version 9.0 solves several of these problems.",source:"@site/docs/MigrationV9.md",sourceDirName:".",slug:"/migration-v9",permalink:"/react-native-testing-library/docs/migration-v9",draft:!1,unlisted:!1,editUrl:"https://github.com/callstack/react-native-testing-library/blob/main/website/docs/MigrationV9.md",tags:[],version:"current",frontMatter:{id:"migration-v9",title:"Migration to 9.0"},sidebar:"docs",previous:{title:"Migration to 11.0",permalink:"/react-native-testing-library/docs/migration-v11"},next:{title:"Migration to 7.0",permalink:"/react-native-testing-library/docs/migration-v7"}},c={},d=[{value:"Support for text match options a.k.a string precision API",id:"support-for-text-match-options-aka-string-precision-api",level:2},{value:"Reverted matching text across several nodes",id:"reverted-matching-text-across-several-nodes",level:2},{value:"Future plans",id:"future-plans",level:2}];function u(e){const t={a:"a",admonition:"admonition",code:"code",h2:"h2",p:"p",pre:"pre",...(0,r.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsxs)(t.p,{children:["Version 7.0 brought React Native Testing Library into the ",(0,i.jsx)(t.code,{children:"@testing-library"})," family. Since it has been implemented independently from its web counterpart \u2013 the React Testing Library \u2013 there are some differences in the API and behavior. Version 9.0 solves several of these problems."]}),"\n",(0,i.jsx)(a.Z,{toc:d}),"\n",(0,i.jsx)(t.h2,{id:"support-for-text-match-options-aka-string-precision-api",children:"Support for text match options a.k.a string precision API"}),"\n",(0,i.jsx)(t.p,{children:"This is a backward compatible change."}),"\n",(0,i.jsxs)(t.p,{children:["When querying text, it is now possible to pass a ",(0,i.jsx)(t.a,{href:"https://callstack.github.io/react-native-testing-library/docs/api-queries/#textmatch",children:(0,i.jsx)(t.code,{children:"TextMatch"})})," to most text based queries, which lets you configure how ",(0,i.jsx)(t.code,{children:"@testing-library/react-native"})," should match your text. For instance, passing ",(0,i.jsx)(t.code,{children:"exact: false"})," will allow matching substrings and will ignore case:"]}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-jsx",children:"const { getByText } = render(Hello World);\n\ngetByText('Hello World'); // Matches\ngetByText('Hello'); // Doesn't match\ngetByText('hello', { exact: false }); // ignore case-sensitivity and does partial matching\n"})}),"\n",(0,i.jsxs)(t.p,{children:["Please note that the ",(0,i.jsx)(t.code,{children:"findBy*"})," queries used to take a ",(0,i.jsx)(t.code,{children:"waitForOptions"})," parameter as a second argument, which has now been moved to the third argument:"]}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-diff",children:"-findByText('Hello world', { timeout: 3000 }); // old findBy* API\n+findByText('Hello world', {}, { timeout: 3000 }); // new findBy* API\n"})}),"\n",(0,i.jsxs)(t.p,{children:["For backward compatibility RNTL v9 can still read ",(0,i.jsx)(t.code,{children:"waitForOptions"})," from the second argument but will print a deprecation warning."]}),"\n",(0,i.jsx)(t.h2,{id:"reverted-matching-text-across-several-nodes",children:"Reverted matching text across several nodes"}),"\n",(0,i.jsx)(t.admonition,{type:"caution",children:(0,i.jsx)(t.p,{children:"This is a breaking change."})}),"\n",(0,i.jsx)(t.p,{children:"In v1.14 we've introduced a feature allowing to match text when it's spread across several nodes:"}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-tsx",children:"const { getByText } = render(\n \n Hello world\n ,\n);\ngetByText('Hello world'); // matches\n"})}),"\n",(0,i.jsx)(t.p,{children:"However this behavior was different than the web one, and wouldn't always be straightforward to reason about. For instance it could match text nodes far from each other on the screen. It also prevented us from implementing the string precision API. From v9, this type of match will not work."}),"\n",(0,i.jsxs)(t.p,{children:["A work around is to use ",(0,i.jsx)(t.code,{children:"within"}),":"]}),"\n",(0,i.jsx)(t.pre,{children:(0,i.jsx)(t.code,{className:"language-tsx",children:"import {Text} from 'react-native'\nimport {render, within} from '@testing-library/react-native'\n\nconst {getByText} = render(Hello world)\n\nwithin(getByText('Hello', {exact: false})).getByText('world')\n"})}),"\n",(0,i.jsx)(t.h2,{id:"future-plans",children:"Future plans"}),"\n",(0,i.jsx)(t.p,{children:"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."}),"\n",(0,i.jsxs)(t.p,{children:["We're also ",(0,i.jsx)(t.a,{href:"https://github.com/callstack/react-native-testing-library/issues/877",children:"migrating the codebase to TypeScript"}),". Please let us know if you're interested in helping us with this effort."]}),"\n",(0,i.jsx)(t.p,{children:"Stay safe!"})]})}function h(e={}){const{wrapper:t}={...(0,r.a)(),...e.components};return t?(0,i.jsx)(t,{...e,children:(0,i.jsx)(u,{...e})}):u(e)}},1151:(e,t,n)=>{n.d(t,{Z:()=>o,a:()=>s});var i=n(7294);const r={},a=i.createContext(r);function s(e){const t=i.useContext(a);return i.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:s(e.components),i.createElement(a.Provider,{value:t},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/runtime~main.33c6f488.js b/assets/js/runtime~main.33c6f488.js new file mode 100644 index 00000000..9644bf35 --- /dev/null +++ b/assets/js/runtime~main.33c6f488.js @@ -0,0 +1 @@ +(()=>{"use strict";var e,t,a,r,o,n={},b={};function d(e){var t=b[e];if(void 0!==t)return t.exports;var a=b[e]={id:e,loaded:!1,exports:{}};return n[e].call(a.exports,a,a.exports,d),a.loaded=!0,a.exports}d.m=n,d.c=b,e=[],d.O=(t,a,r,o)=>{if(!a){var n=1/0;for(i=0;i=o)&&Object.keys(d.O).every((e=>d.O[e](a[f])))?a.splice(f--,1):(b=!1,o0&&e[i-1][2]>o;i--)e[i]=e[i-1];e[i]=[a,r,o]},d.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return d.d(t,{a:t}),t},a=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,d.t=function(e,r){if(1&r&&(e=this(e)),8&r)return e;if("object"==typeof e&&e){if(4&r&&e.__esModule)return e;if(16&r&&"function"==typeof e.then)return e}var o=Object.create(null);d.r(o);var n={};t=t||[null,a({}),a([]),a(a)];for(var b=2&r&&e;"object"==typeof b&&!~t.indexOf(b);b=a(b))Object.getOwnPropertyNames(b).forEach((t=>n[t]=()=>e[t]));return n.default=()=>e,d.d(o,n),o},d.d=(e,t)=>{for(var a in t)d.o(t,a)&&!d.o(e,a)&&Object.defineProperty(e,a,{enumerable:!0,get:t[a]})},d.f={},d.e=e=>Promise.all(Object.keys(d.f).reduce(((t,a)=>(d.f[a](e,t),t)),[])),d.u=e=>"assets/js/"+({53:"935f2afb",63:"8a6052eb",94:"1bdd165f",126:"3c6c3bb0",154:"f2d2b077",195:"c4f5d8e4",278:"01df2f6c",288:"ad895e75",298:"c8229a80",350:"b5dde711",368:"a94703ab",381:"501445cb",430:"7ad239b9",434:"0f1b22a8",456:"14f61f32",471:"d24847ef",494:"698581a0",518:"a7bd4aaa",618:"559cb848",625:"77ba9e12",661:"5e95c892",671:"1c6b47cb",690:"f69ec364",725:"add06ab1",884:"d77361a5",918:"17896441",920:"1a4e3797",940:"aa9e97dd",951:"6bbd6f71",968:"a4410d65"}[e]||e)+"."+{53:"acfe3c54",63:"d288d3e8",72:"57ebe618",94:"0d02bf07",126:"ac86c9bb",154:"1fe6a2cf",195:"0593c39e",278:"9ce2aeb0",288:"fba69aeb",298:"1e5ae667",350:"fb96c550",368:"310ffec2",381:"c86ede60",426:"dc1cd7d1",430:"d78ac751",434:"4658a0fe",456:"07c43acc",471:"a32f7301",494:"eb08a5e7",518:"1d72542c",618:"2f5d0875",625:"319083fc",661:"dd48221b",671:"0063f2b8",690:"1556e56b",725:"50727a9c",884:"ebc4b2b7",894:"c8bd6124",918:"0a1e7ec5",920:"592ec7e6",940:"30cf9ea0",945:"8f5c5b7a",951:"71aba00c",968:"b5d7163d"}[e]+".js",d.miniCssF=e=>{},d.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),d.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r={},o="react-native-testing-library-website:",d.l=(e,t,a,n)=>{if(r[e])r[e].push(t);else{var b,f;if(void 0!==a)for(var c=document.getElementsByTagName("script"),i=0;i{b.onerror=b.onload=null,clearTimeout(s);var o=r[e];if(delete r[e],b.parentNode&&b.parentNode.removeChild(b),o&&o.forEach((e=>e(a))),t)return t(a)},s=setTimeout(u.bind(null,void 0,{type:"timeout",target:b}),12e4);b.onerror=u.bind(null,b.onerror),b.onload=u.bind(null,b.onload),f&&document.head.appendChild(b)}},d.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},d.p="/react-native-testing-library/",d.gca=function(e){return e={17896441:"918","935f2afb":"53","8a6052eb":"63","1bdd165f":"94","3c6c3bb0":"126",f2d2b077:"154",c4f5d8e4:"195","01df2f6c":"278",ad895e75:"288",c8229a80:"298",b5dde711:"350",a94703ab:"368","501445cb":"381","7ad239b9":"430","0f1b22a8":"434","14f61f32":"456",d24847ef:"471","698581a0":"494",a7bd4aaa:"518","559cb848":"618","77ba9e12":"625","5e95c892":"661","1c6b47cb":"671",f69ec364:"690",add06ab1:"725",d77361a5:"884","1a4e3797":"920",aa9e97dd:"940","6bbd6f71":"951",a4410d65:"968"}[e]||e,d.p+d.u(e)},(()=>{var e={303:0,532:0};d.f.j=(t,a)=>{var r=d.o(e,t)?e[t]:void 0;if(0!==r)if(r)a.push(r[2]);else if(/^(303|532)$/.test(t))e[t]=0;else{var o=new Promise(((a,o)=>r=e[t]=[a,o]));a.push(r[2]=o);var n=d.p+d.u(t),b=new Error;d.l(n,(a=>{if(d.o(e,t)&&(0!==(r=e[t])&&(e[t]=void 0),r)){var o=a&&("load"===a.type?"missing":a.type),n=a&&a.target&&a.target.src;b.message="Loading chunk "+t+" failed.\n("+o+": "+n+")",b.name="ChunkLoadError",b.type=o,b.request=n,r[1](b)}}),"chunk-"+t,t)}},d.O.j=t=>0===e[t];var t=(t,a)=>{var r,o,n=a[0],b=a[1],f=a[2],c=0;if(n.some((t=>0!==e[t]))){for(r in b)d.o(b,r)&&(d.m[r]=b[r]);if(f)var i=f(d)}for(t&&t(a);c{"use strict";var e,t,a,r,f,o={},d={};function n(e){var t=d[e];if(void 0!==t)return t.exports;var a=d[e]={id:e,loaded:!1,exports:{}};return o[e].call(a.exports,a,a.exports,n),a.loaded=!0,a.exports}n.m=o,n.c=d,e=[],n.O=(t,a,r,f)=>{if(!a){var o=1/0;for(c=0;c=f)&&Object.keys(n.O).every((e=>n.O[e](a[b])))?a.splice(b--,1):(d=!1,f0&&e[c-1][2]>f;c--)e[c]=e[c-1];e[c]=[a,r,f]},n.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return n.d(t,{a:t}),t},a=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,n.t=function(e,r){if(1&r&&(e=this(e)),8&r)return e;if("object"==typeof e&&e){if(4&r&&e.__esModule)return e;if(16&r&&"function"==typeof e.then)return e}var f=Object.create(null);n.r(f);var o={};t=t||[null,a({}),a([]),a(a)];for(var d=2&r&&e;"object"==typeof d&&!~t.indexOf(d);d=a(d))Object.getOwnPropertyNames(d).forEach((t=>o[t]=()=>e[t]));return o.default=()=>e,n.d(f,o),f},n.d=(e,t)=>{for(var a in t)n.o(t,a)&&!n.o(e,a)&&Object.defineProperty(e,a,{enumerable:!0,get:t[a]})},n.f={},n.e=e=>Promise.all(Object.keys(n.f).reduce(((t,a)=>(n.f[a](e,t),t)),[])),n.u=e=>"assets/js/"+({53:"935f2afb",63:"8a6052eb",94:"1bdd165f",126:"3c6c3bb0",154:"f2d2b077",195:"c4f5d8e4",278:"01df2f6c",288:"ad895e75",298:"c8229a80",350:"b5dde711",368:"a94703ab",381:"501445cb",430:"7ad239b9",434:"0f1b22a8",456:"14f61f32",471:"d24847ef",494:"698581a0",518:"a7bd4aaa",618:"559cb848",625:"77ba9e12",661:"5e95c892",671:"1c6b47cb",690:"f69ec364",725:"add06ab1",884:"d77361a5",918:"17896441",920:"1a4e3797",940:"aa9e97dd",951:"6bbd6f71",968:"a4410d65"}[e]||e)+"."+{53:"acfe3c54",63:"d288d3e8",72:"57ebe618",94:"0d02bf07",126:"ac86c9bb",154:"1fe6a2cf",195:"0593c39e",278:"9ce2aeb0",288:"fba69aeb",298:"87ec1e8f",350:"fb96c550",368:"310ffec2",381:"c86ede60",426:"dc1cd7d1",430:"9d775967",434:"4658a0fe",456:"07c43acc",471:"a32f7301",494:"65ef15c7",518:"1d72542c",618:"2f5d0875",625:"7c7fa4d8",661:"dd48221b",671:"0063f2b8",690:"e1bd5bf9",725:"a1119996",884:"9a82e889",894:"c8bd6124",918:"0a1e7ec5",920:"592ec7e6",940:"30cf9ea0",945:"8f5c5b7a",951:"71aba00c",968:"b5d7163d"}[e]+".js",n.miniCssF=e=>{},n.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r={},f="react-native-testing-library-website:",n.l=(e,t,a,o)=>{if(r[e])r[e].push(t);else{var d,b;if(void 0!==a)for(var i=document.getElementsByTagName("script"),c=0;c{d.onerror=d.onload=null,clearTimeout(s);var f=r[e];if(delete r[e],d.parentNode&&d.parentNode.removeChild(d),f&&f.forEach((e=>e(a))),t)return t(a)},s=setTimeout(u.bind(null,void 0,{type:"timeout",target:d}),12e4);d.onerror=u.bind(null,d.onerror),d.onload=u.bind(null,d.onload),b&&document.head.appendChild(d)}},n.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.p="/react-native-testing-library/",n.gca=function(e){return e={17896441:"918","935f2afb":"53","8a6052eb":"63","1bdd165f":"94","3c6c3bb0":"126",f2d2b077:"154",c4f5d8e4:"195","01df2f6c":"278",ad895e75:"288",c8229a80:"298",b5dde711:"350",a94703ab:"368","501445cb":"381","7ad239b9":"430","0f1b22a8":"434","14f61f32":"456",d24847ef:"471","698581a0":"494",a7bd4aaa:"518","559cb848":"618","77ba9e12":"625","5e95c892":"661","1c6b47cb":"671",f69ec364:"690",add06ab1:"725",d77361a5:"884","1a4e3797":"920",aa9e97dd:"940","6bbd6f71":"951",a4410d65:"968"}[e]||e,n.p+n.u(e)},(()=>{var e={303:0,532:0};n.f.j=(t,a)=>{var r=n.o(e,t)?e[t]:void 0;if(0!==r)if(r)a.push(r[2]);else if(/^(303|532)$/.test(t))e[t]=0;else{var f=new Promise(((a,f)=>r=e[t]=[a,f]));a.push(r[2]=f);var o=n.p+n.u(t),d=new Error;n.l(o,(a=>{if(n.o(e,t)&&(0!==(r=e[t])&&(e[t]=void 0),r)){var f=a&&("load"===a.type?"missing":a.type),o=a&&a.target&&a.target.src;d.message="Loading chunk "+t+" failed.\n("+f+": "+o+")",d.name="ChunkLoadError",d.type=f,d.request=o,r[1](d)}}),"chunk-"+t,t)}},n.O.j=t=>0===e[t];var t=(t,a)=>{var r,f,o=a[0],d=a[1],b=a[2],i=0;if(o.some((t=>0!==e[t]))){for(r in d)n.o(d,r)&&(n.m[r]=d[r]);if(b)var c=b(n)}for(t&&t(a);i Queries | React Native Testing Library - + @@ -43,7 +43,7 @@ below.

  • View host elements need an explicit accessible prop set to true
  • Some React Native composite components like Pressable & TouchableOpacity render host View element with accessible prop already set.
  • -
    import { render, screen } from '@testing-library/react-native';

    render(
    <Pressable accessibilityRole="button" disabled>
    <Text>Hello</Text>
    </Pressable>
    );
    const element = screen.getByRole('button');
    const element2 = screen.getByRole('button', { name: 'Hello' });
    const element3 = screen.getByRole('button', { name: 'Hello', disabled: true });
    +
    import { render, screen } from '@testing-library/react-native';

    render(
    <Pressable accessibilityRole="button" disabled>
    <Text>Hello</Text>
    </Pressable>,
    );
    const element = screen.getByRole('button');
    const element2 = screen.getByRole('button', { name: 'Hello' });
    const element3 = screen.getByRole('button', { name: 'Hello', disabled: true });

    Options​

    • @@ -195,7 +195,7 @@ getByAccessibilityValue, getAllByAccessibilityValue, queryByAccessibilityValue,

      You can configure the default value with the configure function.

      This option is also available as hidden alias for compatibility with React Testing Library.

      Examples

      -
      render(<Text style={{ display: 'none' }}>Hidden from accessibility</Text>);

      // Exclude hidden elements
      expect(
      screen.queryByText('Hidden from accessibility', {
      includeHiddenElements: false,
      })
      ).not.toBeOnTheScreen();

      // Include hidden elements
      expect(screen.getByText('Hidden from accessibility')).toBeOnTheScreen();
      expect(
      screen.getByText('Hidden from accessibility', { includeHiddenElements: true })
      ).toBeOnTheScreen();
      +
      render(<Text style={{ display: 'none' }}>Hidden from accessibility</Text>);

      // Exclude hidden elements
      expect(
      screen.queryByText('Hidden from accessibility', {
      includeHiddenElements: false,
      }),
      ).not.toBeOnTheScreen();

      // Include hidden elements
      expect(screen.getByText('Hidden from accessibility')).toBeOnTheScreen();
      expect(
      screen.getByText('Hidden from accessibility', { includeHiddenElements: true }),
      ).toBeOnTheScreen();

      TextMatch type​

      type TextMatch = string | RegExp;

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

      diff --git a/docs/api.html b/docs/api.html index 625a093f..5ec4ad4b 100644 --- a/docs/api.html +++ b/docs/api.html @@ -4,7 +4,7 @@ API | React Native Testing Library - + @@ -94,26 +94,26 @@ more realistic event simulation by emitting a sequence of events with proper event objects that mimic React Native runtime behavior.

      Use Fire Event for cases not supported by User Event and for triggering event handlers on composite components.

      fireEvent API allows you to trigger all kind of event handlers on both host and composite components. It will try to invoke a single event handler traversing the component tree bottom-up from passed element and trying to find enabled event handler named onXxx when xxx is the name of the event passed.

      Unlike User Event, this API does not automatically pass event object to event handler, this is responsibility of the user to construct such object.

      -
      import { render, screen, fireEvent } from '@testing-library/react-native';

      test('fire changeText event', () => {
      const onEventMock = jest.fn();
      render(
      // MyComponent renders TextInput which has a placeholder 'Enter details'
      // and with `onChangeText` bound to handleChangeText
      <MyComponent handleChangeText={onEventMock} />
      );

      fireEvent(screen.getByPlaceholderText('change'), 'onChangeText', 'ab');
      expect(onEventMock).toHaveBeenCalledWith('ab');
      });
      +
      import { render, screen, fireEvent } from '@testing-library/react-native';

      test('fire changeText event', () => {
      const onEventMock = jest.fn();
      render(
      // MyComponent renders TextInput which has a placeholder 'Enter details'
      // and with `onChangeText` bound to handleChangeText
      <MyComponent handleChangeText={onEventMock} />,
      );

      fireEvent(screen.getByPlaceholderText('change'), 'onChangeText', 'ab');
      expect(onEventMock).toHaveBeenCalledWith('ab');
      });
      note

      Please note that from version 7.0 fireEvent performs checks that should prevent events firing on disabled elements.

      An example using fireEvent with native events that aren't already aliased by the fireEvent api.

      -
      import { TextInput, View } from 'react-native';
      import { fireEvent, render } from '@testing-library/react-native';

      const onBlurMock = jest.fn();

      render(
      <View>
      <TextInput placeholder="my placeholder" onBlur={onBlurMock} />
      </View>
      );

      // you can omit the `on` prefix
      fireEvent(screen.getByPlaceholderText('my placeholder'), 'blur');
      +
      import { TextInput, View } from 'react-native';
      import { fireEvent, render } from '@testing-library/react-native';

      const onBlurMock = jest.fn();

      render(
      <View>
      <TextInput placeholder="my placeholder" onBlur={onBlurMock} />
      </View>,
      );

      // you can omit the `on` prefix
      fireEvent(screen.getByPlaceholderText('my placeholder'), 'blur');

      FireEvent exposes convenience methods for common events like: press, changeText, scroll.

      fireEvent.press​

      fireEvent.press: (element: ReactTestInstance, ...data: Array<any>) => void
      note

      It is recommended to use the User Event press() helper instead as it offers more realistic simulation of press interaction, including pressable support.

      Invokes press event handler on the element or parent element in the tree.

      -
      import { View, Text, TouchableOpacity } from 'react-native';
      import { render, screen, fireEvent } from '@testing-library/react-native';

      const onPressMock = jest.fn();
      const eventData = {
      nativeEvent: {
      pageX: 20,
      pageY: 30,
      },
      };

      render(
      <View>
      <TouchableOpacity onPress={onPressMock}>
      <Text>Press me</Text>
      </TouchableOpacity>
      </View>
      );

      fireEvent.press(screen.getByText('Press me'), eventData);
      expect(onPressMock).toHaveBeenCalledWith(eventData);
      +
      import { View, Text, TouchableOpacity } from 'react-native';
      import { render, screen, fireEvent } from '@testing-library/react-native';

      const onPressMock = jest.fn();
      const eventData = {
      nativeEvent: {
      pageX: 20,
      pageY: 30,
      },
      };

      render(
      <View>
      <TouchableOpacity onPress={onPressMock}>
      <Text>Press me</Text>
      </TouchableOpacity>
      </View>,
      );

      fireEvent.press(screen.getByText('Press me'), eventData);
      expect(onPressMock).toHaveBeenCalledWith(eventData);

      fireEvent.changeText​

      fireEvent.changeText: (element: ReactTestInstance, ...data: Array<any>) => void
      note

      It is recommended to use the User Event type() helper instead as it offers more realistic simulation of text change interaction, including key-by-key typing, element focus, and other editing events.

      Invokes changeText event handler on the element or parent element in the tree.

      -
      import { View, TextInput } from 'react-native';
      import { render, screen, fireEvent } from '@testing-library/react-native';

      const onChangeTextMock = jest.fn();
      const CHANGE_TEXT = 'content';

      render(
      <View>
      <TextInput placeholder="Enter data" onChangeText={onChangeTextMock} />
      </View>
      );

      fireEvent.changeText(screen.getByPlaceholderText('Enter data'), CHANGE_TEXT);
      +
      import { View, TextInput } from 'react-native';
      import { render, screen, fireEvent } from '@testing-library/react-native';

      const onChangeTextMock = jest.fn();
      const CHANGE_TEXT = 'content';

      render(
      <View>
      <TextInput placeholder="Enter data" onChangeText={onChangeTextMock} />
      </View>,
      );

      fireEvent.changeText(screen.getByPlaceholderText('Enter data'), CHANGE_TEXT);

      fireEvent.scroll​

      fireEvent.scroll: (element: ReactTestInstance, ...data: Array<any>) => void

      Invokes scroll event handler on the element or parent element in the tree.

      On a ScrollView​

      -
      import { ScrollView, Text } from 'react-native';
      import { render, screen, fireEvent } from '@testing-library/react-native';

      const onScrollMock = jest.fn();
      const eventData = {
      nativeEvent: {
      contentOffset: {
      y: 200,
      },
      },
      };

      render(
      <ScrollView onScroll={onScrollMock}>
      <Text>XD</Text>
      </ScrollView>
      );

      fireEvent.scroll(screen.getByText('scroll-view'), eventData);
      +
      import { ScrollView, Text } from 'react-native';
      import { render, screen, fireEvent } from '@testing-library/react-native';

      const onScrollMock = jest.fn();
      const eventData = {
      nativeEvent: {
      contentOffset: {
      y: 200,
      },
      },
      };

      render(
      <ScrollView onScroll={onScrollMock}>
      <Text>XD</Text>
      </ScrollView>,
      );

      fireEvent.scroll(screen.getByText('scroll-view'), eventData);
      note

      Prefer using user.scrollTo over fireEvent.scroll for ScrollView, FlatList, and SectionList components. User Event provides a more realistic event simulation based on React Native runtime behavior.

      Helper functions​

      waitFor​

      @@ -121,9 +121,9 @@ more realistic event simulation by emitting a sequence of events with proper eve
    • Example code

    Defined as:

    -
    function waitFor<T>(
    expectation: () => T,
    { timeout: number = 1000, interval: number = 50 }
    ): Promise<T> {}
    +
    function waitFor<T>(
    expectation: () => T,
    { timeout: number = 1000, interval: number = 50 },
    ): Promise<T> {}

    Waits for a period of time for the expectation callback to pass. waitFor may run the callback a number of times until timeout is reached, as specified by the timeout and interval options. The callback must throw an error when the expectation is not met. Returning any value, including a falsy one, will be treated as meeting the expectation, and the callback result will be returned to the caller of waitFor function.

    -
    await waitFor(() => expect(mockFunction).toHaveBeenCalledWith())
    +
    await waitFor(() => expect(mockFunction).toHaveBeenCalledWith());

    waitFor function will be executing expectation callback every interval (default: every 50 ms) until timeout (default: 1000 ms) is reached. The repeated execution of callback is stopped as soon as it does not throw an error, in such case the value returned by the callback is returned to waitFor caller. Otherwise, when it reaches the timeout, the final error thrown by expectation will be re-thrown by waitFor to the calling code.

    // ❌ `waitFor` will return immediately because callback does not throw
    await waitFor(() => false);

    waitFor is an async function so you need to await the result to pause test execution.

    @@ -146,7 +146,7 @@ more realistic event simulation by emitting a sequence of events with proper eve
  • [Example code]https://github.com/callstack/react-native-testing-library/blob/main/src/__tests__/wait-for-element-to-be-removed.test.tsx)
  • Defined as:

    -
    function waitForElementToBeRemoved<T>(
    expectation: () => T,
    { timeout: number = 4500, interval: number = 50 }
    ): Promise<T> {}
    +
    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, screen, waitForElementToBeRemoved } from '@testing-library/react-native';

    test('waiting for an Banana to be removed', async () => {
    render(<Banana />);

    await waitForElementToBeRemoved(() => screen.getByText('Banana ready'));
    });

    This method expects that the element is initially 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.

    @@ -181,7 +181,7 @@ more realistic event simulation by emitting a sequence of events with proper eve

    Failing to call cleanup when you've called render could result in a memory leak and tests which are not "idempotent" (which can lead to difficult to debug errors in your tests).

    renderHook API​

    Defined as:

    -
    function renderHook<Result, Props>(
    callback: (props?: Props) => Result,
    options?: RenderHookOptions<Props>
    ): RenderHookResult<Result, Props>;
    +
    function renderHook<Result, Props>(
    callback: (props?: Props) => Result,
    options?: RenderHookOptions<Props>,
    ): RenderHookResult<Result, Props>;

    Renders a test component that will call the provided callback, including any hooks it calls, every time it renders. Returns RenderHookResult object, which you can interact with.

    import { renderHook } from '@testing-library/react-native';
    import { useCount } from '../useCount';

    it('should increment count', () => {
    const { result } = renderHook(() => useCount());

    expect(result.current.count).toBe(0);
    act(() => {
    // Note that you should wrap the calls to functions your hook returns with `act` if they trigger an update of your hook's state to ensure pending useEffects are run before your next assertion.
    result.current.increment();
    });
    expect(result.current.count).toBe(1);
    });
    // useCount.js
    export const useCount = () => {
    const [count, setCount] = useState(0);
    const increment = () => setCount((previousCount) => previousCount + 1);

    return { count, increment };
    };
    diff --git a/docs/community-resources.html b/docs/community-resources.html index ad79adab..db1cd860 100644 --- a/docs/community-resources.html +++ b/docs/community-resources.html @@ -4,13 +4,13 @@ Community Resources | React Native Testing Library - +

    Community Resources

      -
    • The Testing Trophy and Testing Classifications by Kent C. Dodds (2021) - classic article explaining testing philosophy behind all Testing Library implementations.
    • +
    • The Testing Trophy and Testing Classifications by Kent C. Dodds (2021) - classic article explaining testing philosophy behind all Testing Library implementations.
    • Common mistakes with React Testing Library by Kent C. Dodds (2020) - classic article explaining React Testing Library best practices, highly applicable to RNTL as well.
    • React Native — UI Testing (Ultimate Guide) by Anisur Rahman - comprehensive guide to RNTL testing
    • React Native Testing examples repo by Steve Galili - extensive repo with RN testing examples for RNTL and Maestro
    • diff --git a/docs/eslint-plugin-testing-library.html b/docs/eslint-plugin-testing-library.html index 0052abba..28df499a 100644 --- a/docs/eslint-plugin-testing-library.html +++ b/docs/eslint-plugin-testing-library.html @@ -4,7 +4,7 @@ ESLint Plugin Testing Library Compatibility | React Native Testing Library - + diff --git a/docs/faq.html b/docs/faq.html index ba5a47f6..81d80fb7 100644 --- a/docs/faq.html +++ b/docs/faq.html @@ -4,7 +4,7 @@ FAQ | React Native Testing Library - + diff --git a/docs/getting-started.html b/docs/getting-started.html index 586eceb2..347a62b3 100644 --- a/docs/getting-started.html +++ b/docs/getting-started.html @@ -4,7 +4,7 @@ Getting Started | React Native Testing Library - + diff --git a/docs/how-should-i-query.html b/docs/how-should-i-query.html index 86fdfc17..b5edf0ad 100644 --- a/docs/how-should-i-query.html +++ b/docs/how-should-i-query.html @@ -4,7 +4,7 @@ How Should I Query? | React Native Testing Library - + diff --git a/docs/jest-matchers.html b/docs/jest-matchers.html index a0ee02eb..a9649fba 100644 --- a/docs/jest-matchers.html +++ b/docs/jest-matchers.html @@ -4,7 +4,7 @@ Jest Matchers | React Native Testing Library - + diff --git a/docs/migration-jest-native.html b/docs/migration-jest-native.html index 806e145e..ae8b967b 100644 --- a/docs/migration-jest-native.html +++ b/docs/migration-jest-native.html @@ -4,7 +4,7 @@ Migration from Jest Native matchers | React Native Testing Library - + diff --git a/docs/migration-v11.html b/docs/migration-v11.html index 9852338e..fc77d24f 100644 --- a/docs/migration-v11.html +++ b/docs/migration-v11.html @@ -4,7 +4,7 @@ Migration to 11.0 | React Native Testing Library - + @@ -15,7 +15,7 @@

      If you use fake timers in any of your tests you should update your Jest dependencies to version 28. This is due to the fact that jest.useFakeTimers() config structure has changed.

      Refactor legacy waitForOptions position​

      In version 9 we introducted query options parameters for each query type. This affected all findBy and findAllBy queries because their signatures changed e.g. from:

      -
      function findByText(text: TextMatch, waitForOptions?: WaitForOptions)
      function findAllByText(text: TextMatch, waitForOptions?: WaitForOptions)
      +
      function findByText(text: TextMatch, waitForOptions?: WaitForOptions);
      function findAllByText(text: TextMatch, waitForOptions?: WaitForOptions);

      to

      function findByText(text: TextMatch, options?: TextMatchOptions, waitForOptions?: WaitForOptions)
      function findAllByText(text: TextMatch, options?: TextMatchOptions, waitForOptions?: WaitForOptions)

      In order to facilitate transition, in version 9 and 10, we provided a temporary possibility to pass WaitForOptions like timeout, interval, etc inside options argument. From this release we require passing these as the proper third parameter.

      diff --git a/docs/migration-v12.html b/docs/migration-v12.html index 9adb2a82..14d378b6 100644 --- a/docs/migration-v12.html +++ b/docs/migration-v12.html @@ -4,7 +4,7 @@ Migration to 12.0 | React Native Testing Library - + diff --git a/docs/migration-v2.html b/docs/migration-v2.html index 5f53c8d1..84d79e4d 100644 --- a/docs/migration-v2.html +++ b/docs/migration-v2.html @@ -4,7 +4,7 @@ Migration to 2.0 | React Native Testing Library - + @@ -33,9 +33,9 @@

    WaitFor API changes​

    We renamed waitForElement function to waitFor for consistency with React Testing Library. Additionally, the signature has slightly changed from:

    -
    export default function waitForElement<T>(
    expectation: () => T,
    timeout?: number,
    interval?: number
    ): Promise<T> {}
    +
    export default function waitForElement<T>(
    expectation: () => T,
    timeout?: number,
    interval?: number,
    ): Promise<T> {}

    to:

    -
    export default function waitFor<T>(
    expectation: () => T,
    options: {
    timeout?: number,
    interval?: number,
    }
    ): Promise<T> {}
    +
    export default function waitFor<T>(
    expectation: () => T,
    options: {
    timeout?: number,
    interval?: number,
    },
    ): Promise<T> {}

    Both changes should improve code readibility.

    waitFor calls (and hence also findBy queries) are now wrapped in act by default, so that you should no longer need to use act directly in your tests.

    tip

    You can usually avoid waitFor by a proper use of findBy asynchronous queries. It will result in more streamlined testing experience.

    diff --git a/docs/migration-v7.html b/docs/migration-v7.html index 8ab28d3c..15a001d3 100644 --- a/docs/migration-v7.html +++ b/docs/migration-v7.html @@ -4,7 +4,7 @@ Migration to 7.0 | React Native Testing Library - + diff --git a/docs/migration-v9.html b/docs/migration-v9.html index 22dd6127..f79037e8 100644 --- a/docs/migration-v9.html +++ b/docs/migration-v9.html @@ -4,7 +4,7 @@ Migration to 9.0 | React Native Testing Library - + @@ -20,7 +20,7 @@

    Reverted matching text across several nodes​

    caution

    This is a breaking change.

    In v1.14 we've introduced a feature allowing to match text when it's spread across several nodes:

    -
    const { getByText } = render(
    <Text>
    Hello <Text>world</Text>
    </Text>
    );
    getByText('Hello world'); // matches
    +
    const { getByText } = render(
    <Text>
    Hello <Text>world</Text>
    </Text>,
    );
    getByText('Hello world'); // matches

    However this behavior was different than the web one, and wouldn't always be straightforward to reason about. For instance it could match text nodes far from each other on the screen. It also prevented us from implementing the string precision API. From v9, this type of match will not work.

    A work around is to use within:

    import {Text} from 'react-native'
    import {render, within} from '@testing-library/react-native'

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

    within(getByText('Hello', {exact: false})).getByText('world')
    diff --git a/docs/react-navigation.html b/docs/react-navigation.html index a7c257b3..d619c8e1 100644 --- a/docs/react-navigation.html +++ b/docs/react-navigation.html @@ -4,7 +4,7 @@ React Navigation | React Native Testing Library - + diff --git a/docs/redux-integration.html b/docs/redux-integration.html index f87e9ca4..e5061093 100644 --- a/docs/redux-integration.html +++ b/docs/redux-integration.html @@ -4,7 +4,7 @@ Redux Integration | React Native Testing Library - + @@ -15,7 +15,7 @@

    Test cases​

    Our test is on the components that either dispatch actions on the redux store or read some data from the redux store. This means we will test ./components/AddTodo.js and ./components/TodoList.js. Thus we will create ./components/AddTodo.test.js and ./components/TodoList.test.js

    For ./components/AddTodo.test.js

    -
    import * as React from 'react';
    import { Provider } from 'react-redux';
    import { render, screen, fireEvent } from '@testing-library/react-native';
    import configureStore from '../store';
    import AddTodo from './AddTodo';

    describe('AddTodo component test', () => {
    test('adds a new TODO when the button is pressed', () => {
    const store = configureStore();

    const component = (
    <Provider store={store}>
    <AddTodo />
    </Provider>
    );

    render(component);

    // There is a TextInput.
    // https://github.com/callstack/react-native-testing-library/blob/ae3d4af370487e1e8fedd8219f77225690aefc59/examples/redux/components/AddTodo.js#L24
    const input = screen.getByPlaceholderText(/repository/i);
    expect(input).toBeOnTheScreen();

    const textToEnter = 'This is a random element';
    fireEvent.changeText(input, textToEnter);
    fireEvent.press(screen.getByText('Submit form'));

    const todosState = store.getState().todos;

    expect(todosState.length).toEqual(1);

    expect(todosState).toEqual(
    expect.arrayContaining([
    expect.objectContaining({
    id: 1,
    text: textToEnter,
    date: expect.any(Date),
    }),
    ])
    );
    });
    });
    +
    import * as React from 'react';
    import { Provider } from 'react-redux';
    import { render, screen, fireEvent } from '@testing-library/react-native';
    import configureStore from '../store';
    import AddTodo from './AddTodo';

    describe('AddTodo component test', () => {
    test('adds a new TODO when the button is pressed', () => {
    const store = configureStore();

    const component = (
    <Provider store={store}>
    <AddTodo />
    </Provider>
    );

    render(component);

    // There is a TextInput.
    // https://github.com/callstack/react-native-testing-library/blob/ae3d4af370487e1e8fedd8219f77225690aefc59/examples/redux/components/AddTodo.js#L24
    const input = screen.getByPlaceholderText(/repository/i);
    expect(input).toBeOnTheScreen();

    const textToEnter = 'This is a random element';
    fireEvent.changeText(input, textToEnter);
    fireEvent.press(screen.getByText('Submit form'));

    const todosState = store.getState().todos;

    expect(todosState.length).toEqual(1);

    expect(todosState).toEqual(
    expect.arrayContaining([
    expect.objectContaining({
    id: 1,
    text: textToEnter,
    date: expect.any(Date),
    }),
    ]),
    );
    });
    });

    For ./components/TodoList.test.js

    import * as React from 'react';
    import { Provider } from 'react-redux';
    import { render, screen, fireEvent } from '@testing-library/react-native';
    import configureStore from '../store';
    import TodoList from './TodoList';

    describe('TodoList component test', () => {
    test('it should execute with a store with 4 elements', () => {
    const initialState = {
    todos: [
    { id: 1, text: 'Sing something', date: new Date() },
    { id: 2, text: 'Dance something', date: new Date() },
    { id: 3, text: 'Sleep something', date: new Date() },
    { id: 4, text: 'Sleep something', date: new Date() },
    ],
    };
    const store = configureStore(initialState);

    const component = (
    <Provider store={store}>
    <TodoList />
    </Provider>
    );

    render(component);
    const todoElems = screen.getAllByText(/something/i);

    expect(todoElems.length).toEqual(4);
    });

    test('should execute with 2 elements and end up with 1 after delete', () => {
    const initialState = {
    todos: [
    { id: 1, text: 'Sing something', date: new Date() },
    { id: 2, text: 'Dance something', date: new Date() },
    ],
    };
    const store = configureStore(initialState);

    const component = (
    <Provider store={store}>
    <TodoList />
    </Provider>
    );

    render(component);
    const todoElems = screen.getAllByText(/something/i);

    expect(todoElems.length).toBe(2);

    const buttons = screen.getAllByText('Delete');
    expect(buttons.length).toBe(2);

    fireEvent.press(buttons[0]);
    expect(screen.getAllByText('Delete').length).toBe(1);
    });
    });

    Running tests​

    diff --git a/docs/testing-env.html b/docs/testing-env.html index 794cf1d8..600ccdc3 100644 --- a/docs/testing-env.html +++ b/docs/testing-env.html @@ -4,7 +4,7 @@ Testing Environment | React Native Testing Library - + diff --git a/docs/troubleshooting.html b/docs/troubleshooting.html index 97c83b7a..70ff59ca 100644 --- a/docs/troubleshooting.html +++ b/docs/troubleshooting.html @@ -4,7 +4,7 @@ Troubleshooting | React Native Testing Library - + diff --git a/docs/understanding-act.html b/docs/understanding-act.html index 390d8ce4..ad45fd26 100644 --- a/docs/understanding-act.html +++ b/docs/understanding-act.html @@ -4,7 +4,7 @@ Understanding Act function | React Native Testing Library - + diff --git a/docs/user-event.html b/docs/user-event.html index 873a16ea..e4657f0f 100644 --- a/docs/user-event.html +++ b/docs/user-event.html @@ -4,7 +4,7 @@ User Event | React Native Testing Library - + diff --git a/index.html b/index.html index 89489b9b..08ff3290 100644 --- a/index.html +++ b/index.html @@ -4,7 +4,7 @@ React Native Testing Library | React Native Testing Library - + diff --git a/search.html b/search.html index 981af930..72118c66 100644 --- a/search.html +++ b/search.html @@ -4,7 +4,7 @@ Search the documentation | React Native Testing Library - +