CINXE.COM
<!DOCTYPE html><html lang="en"><head><link rel="preload" href="https://unpkg.com/docsearch.js@2.4.1/dist/cdn/docsearch.min.js" as="script"/><meta charSet="utf-8"/><meta http-equiv="X-UA-Compatible" content="IE=edge"/><meta name="viewport" content="width=device-width, initial-scale=1.0"/><link rel="icon" href="/favicon.ico"/><meta name="apple-mobile-web-app-capable" content="yes"/><link rel="apple-touch-icon" href="/logo-180x180.png"/><meta name="apple-mobile-web-app-title" content="React"/><style data-href="/styles.aa479e982b16a410ac78.css" id="gatsby-global-css">/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:.67em 0}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}[hidden],template{display:none}html{box-sizing:border-box;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;font-weight:400;font-style:normal;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}body{overflow-x:hidden;position:relative}*{margin:0;padding:0}*,:after,:before{box-sizing:inherit}a{color:inherit;text-decoration:none}ol,ul{list-style:none}img{display:inline-block;vertical-align:top}code,pre{font-family:source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace}.scary>blockquote{background-color:rgba(237,51,21,.2)!important;border-left-color:#ed3315!important}.searchbox{display:inline-block;position:relative;width:200px;height:32px!important;white-space:nowrap;box-sizing:border-box;visibility:visible!important}.searchbox .algolia-autocomplete{display:block;width:100%;height:100%}.searchbox__wrapper{width:100%;height:100%;z-index:999;position:relative}.searchbox__input{display:inline-block;box-sizing:border-box;transition:box-shadow .4s ease,background .4s ease;border:0;border-radius:16px;box-shadow:inset 0 0 0 1px #ccc;background:#fff!important;padding:0 26px 0 32px;width:100%;height:100%;vertical-align:middle;white-space:normal;font-size:12px;-webkit-appearance:none;appearance:none}.searchbox__input::-webkit-search-cancel-button,.searchbox__input::-webkit-search-decoration,.searchbox__input::-webkit-search-results-button,.searchbox__input::-webkit-search-results-decoration{display:none}.searchbox__input:hover{box-shadow:inset 0 0 0 1px #b3b3b3}.searchbox__input:active,.searchbox__input:focus{outline:0;box-shadow:inset 0 0 0 1px #aaa;background:#fff}.searchbox__input::-webkit-input-placeholder{color:#aaa}.searchbox__input::placeholder{color:#aaa}.searchbox__submit{position:absolute;top:0;margin:0;border:0;border-radius:16px 0 0 16px;background-color:rgba(69,142,225,0);padding:0;width:32px;height:100%;vertical-align:middle;text-align:center;font-size:inherit;-webkit-user-select:none;user-select:none;right:inherit;left:0}.searchbox__submit:before{display:inline-block;margin-right:-4px;height:100%;vertical-align:middle;content:""}.searchbox__submit:active,.searchbox__submit:hover{cursor:pointer}.searchbox__submit:focus{outline:0}.searchbox__submit svg{width:14px;height:14px;vertical-align:middle;fill:#6d7e96}.searchbox__reset{display:block;position:absolute;top:8px;right:8px;margin:0;border:0;background:none;cursor:pointer;padding:0;font-size:inherit;-webkit-user-select:none;user-select:none;fill:rgba(0,0,0,.5)}.searchbox__reset.hide{display:none}.searchbox__reset:focus{outline:0}.searchbox__reset svg{display:block;margin:4px;width:8px;height:8px}.searchbox__input:valid~.searchbox__reset{display:block;-webkit-animation-name:sbx-reset-in;animation-name:sbx-reset-in;-webkit-animation-duration:.15s;animation-duration:.15s}@-webkit-keyframes sbx-reset-in{0%{-webkit-transform:translate3d(-20%,0,0);transform:translate3d(-20%,0,0);opacity:0}to{-webkit-transform:none;transform:none;opacity:1}}@keyframes sbx-reset-in{0%{-webkit-transform:translate3d(-20%,0,0);transform:translate3d(-20%,0,0);opacity:0}to{-webkit-transform:none;transform:none;opacity:1}}.algolia-autocomplete .ds-dropdown-menu:before{display:block;position:absolute;content:"";width:14px;height:14px;background:#373940;z-index:1000;top:-7px;border-top:1px solid #373940;border-right:1px solid #373940;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);border-radius:2px}.algolia-autocomplete .ds-dropdown-menu{box-shadow:0 1px 0 0 rgba(0,0,0,.2),0 2px 3px 0 rgba(0,0,0,.1)}@media (min-width:601px){.algolia-autocomplete.algolia-autocomplete-right .ds-dropdown-menu{right:0!important;left:inherit!important}.algolia-autocomplete.algolia-autocomplete-right .ds-dropdown-menu:before{right:48px}.algolia-autocomplete .ds-dropdown-menu{top:-6px;border-radius:4px;margin:6px 0 0;padding:0;text-align:left;height:auto;position:relative;background:transparent;border:none;z-index:999;max-width:600px;min-width:500px}}@media (max-width:600px){.algolia-autocomplete .ds-dropdown-menu{z-index:100;position:fixed!important;top:40px!important;left:auto!important;right:1rem!important;width:600px;max-width:calc(100% - 2rem);max-height:calc(100% - 5rem);display:block}.algolia-autocomplete .ds-dropdown-menu:before{right:6rem}}.algolia-autocomplete .ds-dropdown-menu .ds-suggestions{position:relative;z-index:1000}.algolia-autocomplete .ds-dropdown-menu .ds-suggestion{cursor:pointer}.algolia-autocomplete .ds-dropdown-menu [class^=ds-dataset-]{position:relative;border-radius:4px;overflow:auto;padding:0}.algolia-autocomplete .ds-dropdown-menu *{box-sizing:border-box}.algolia-autocomplete .algolia-docsearch-suggestion{position:relative;padding:0;overflow:hidden}.algolia-autocomplete .ds-cursor .algolia-docsearch-suggestion--wrapper{background:#f1f1f1;box-shadow:inset -2px 0 0 #61dafb}.algolia-autocomplete .algolia-docsearch-suggestion--highlight{background:#ffe564;padding:.1em .05em}.algolia-autocomplete .algolia-docsearch-suggestion--category-header .algolia-docsearch-suggestion--category-header-lvl0 .algolia-docsearch-suggestion--highlight,.algolia-autocomplete .algolia-docsearch-suggestion--category-header .algolia-docsearch-suggestion--category-header-lvl1 .algolia-docsearch-suggestion--highlight{color:inherit;background:inherit}.algolia-autocomplete .algolia-docsearch-suggestion--text .algolia-docsearch-suggestion--highlight{padding:0 0 1px;background:inherit;box-shadow:inset 0 -2px 0 0 rgba(69,142,225,.8);color:inherit}.algolia-autocomplete .algolia-docsearch-suggestion--content{display:block;float:right;width:70%;position:relative;padding:5.33333px 0 5.33333px 10.66667px;cursor:pointer}.algolia-autocomplete .algolia-docsearch-suggestion--content:before{content:"";position:absolute;display:block;top:0;height:100%;width:1px;background:#ececec;left:-1px}.algolia-autocomplete .algolia-docsearch-suggestion--category-header{position:relative;display:none;font-size:14px;letter-spacing:.08em;font-weight:700;background-color:#373940;text-transform:uppercase;color:#fff;margin:0;padding:5px 8px}.algolia-autocomplete .algolia-docsearch-suggestion--wrapper{background-color:#fff;width:100%;float:left;padding:8px 0 0}.algolia-autocomplete .algolia-docsearch-suggestion--subcategory-column{float:left;width:30%;display:none;text-align:right;position:relative;padding:5.33333px 10.66667px;color:#777;font-size:.9em;word-wrap:break-word}.algolia-autocomplete .algolia-docsearch-suggestion--subcategory-column:before{content:"";position:absolute;display:block;top:0;height:100%;width:1px;background:#ececec;right:0}.algolia-autocomplete .algolia-docsearch-suggestion--subcategory-column .algolia-docsearch-suggestion--highlight{background-color:inherit;color:inherit}.algolia-autocomplete .algolia-docsearch-suggestion--subcategory-inline{display:none}.algolia-autocomplete .algolia-docsearch-suggestion--title{margin-bottom:4px;color:#02060c;font-size:.9em;font-weight:700}.algolia-autocomplete .algolia-docsearch-suggestion--text{display:block;line-height:1.2em;font-size:.85em;color:#63676d;padding-right:2px}.algolia-autocomplete .algolia-docsearch-suggestion--no-results{width:100%;padding:8px 0;text-align:center;font-size:1.2em;background-color:#373940;margin-top:-8px}.algolia-autocomplete .algolia-docsearch-suggestion--no-results .algolia-docsearch-suggestion--text{color:#fff;margin-top:4px}.algolia-autocomplete .algolia-docsearch-suggestion--no-results:before{display:none}.algolia-autocomplete .algolia-docsearch-suggestion code{padding:1px 5px;font-size:90%;border:none;color:#222;background-color:#ebebeb;border-radius:3px;font-family:source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace}.algolia-autocomplete .algolia-docsearch-suggestion code .algolia-docsearch-suggestion--highlight{background:none}.algolia-autocomplete .algolia-docsearch-suggestion.algolia-docsearch-suggestion__main .algolia-docsearch-suggestion--category-header,.algolia-autocomplete .algolia-docsearch-suggestion.algolia-docsearch-suggestion__secondary .algolia-docsearch-suggestion--subcategory-column{display:block}.algolia-autocomplete .algolia-docsearch-footer{background-color:#fff;width:100%;height:30px;z-index:2000;float:right;font-size:0;line-height:0}.algolia-autocomplete .algolia-docsearch-footer--logo{background-image:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 130 18"><defs><linearGradient id="a" x1="-36.87%" x2="129.43%" y1="134.94%" y2="-27.7%"><stop stop-color="%2300AEFF" offset="0%"/><stop stop-color="%233369E7" offset="100%"/></linearGradient></defs><g fill="none" fill-rule="evenodd"><path fill="url(%23a)" d="M59.4.02h13.3a2.37 2.37 0 0 1 2.38 2.37V15.6a2.37 2.37 0 0 1-2.38 2.36H59.4a2.37 2.37 0 0 1-2.38-2.36V2.38A2.37 2.37 0 0 1 59.4.02z"/><path fill="%23FFF" d="M66.26 4.56c-2.82 0-5.1 2.27-5.1 5.08 0 2.8 2.28 5.07 5.1 5.07 2.8 0 5.1-2.26 5.1-5.07 0-2.8-2.28-5.07-5.1-5.07zm0 8.65c-2 0-3.6-1.6-3.6-3.56 0-1.97 1.6-3.58 3.6-3.58 1.98 0 3.6 1.6 3.6 3.58a3.58 3.58 0 0 1-3.6 3.57zm0-6.4v2.66c0 .07.08.13.15.1l2.4-1.24c.04-.02.06-.1.03-.14a2.96 2.96 0 0 0-2.46-1.5c-.06 0-.1.05-.1.1zm-3.33-1.96l-.3-.3a.78.78 0 0 0-1.12 0l-.36.36a.77.77 0 0 0 0 1.1l.3.3c.05.05.13.04.17 0 .2-.25.4-.5.6-.7.23-.23.46-.43.7-.6.07-.04.07-.1.03-.16zm5-.8V3.4a.78.78 0 0 0-.78-.78h-1.83a.78.78 0 0 0-.78.78v.63c0 .07.06.12.14.1a5.74 5.74 0 0 1 1.58-.22c.52 0 1.04.07 1.54.2a.1.1 0 0 0 .13-.1z"/><path fill="%23182359" d="M102.16 13.76c0 1.46-.37 2.52-1.12 3.2-.75.67-1.9 1-3.44 1-.56 0-1.74-.1-2.67-.3l.34-1.7c.78.17 1.82.2 2.36.2.86 0 1.48-.16 1.84-.5.37-.36.55-.88.55-1.57v-.35a6.37 6.37 0 0 1-.84.3 4.15 4.15 0 0 1-1.2.17 4.5 4.5 0 0 1-1.6-.28 3.38 3.38 0 0 1-1.26-.82 3.74 3.74 0 0 1-.8-1.35c-.2-.54-.3-1.5-.3-2.2 0-.67.1-1.5.3-2.06a3.92 3.92 0 0 1 .9-1.43 4.12 4.12 0 0 1 1.45-.92 5.3 5.3 0 0 1 1.94-.37c.7 0 1.35.1 1.97.2a15.86 15.86 0 0 1 1.6.33v8.46zm-5.95-4.2c0 .9.2 1.88.6 2.3.4.4.9.62 1.53.62.34 0 .66-.05.96-.15a2.75 2.75 0 0 0 .73-.33V6.7a8.53 8.53 0 0 0-1.42-.17c-.76-.02-1.36.3-1.77.8-.4.5-.62 1.4-.62 2.23zm16.13 0c0 .72-.1 1.26-.32 1.85a4.4 4.4 0 0 1-.9 1.53c-.38.42-.85.75-1.4.98-.54.24-1.4.37-1.8.37-.43 0-1.27-.13-1.8-.36a4.1 4.1 0 0 1-1.4-.97 4.5 4.5 0 0 1-.92-1.52 5.04 5.04 0 0 1-.33-1.84c0-.72.1-1.4.32-2 .22-.6.53-1.1.92-1.5.4-.43.86-.75 1.4-.98a4.55 4.55 0 0 1 1.78-.34 4.7 4.7 0 0 1 1.8.34c.54.23 1 .55 1.4.97.38.42.68.92.9 1.5.23.6.35 1.3.35 2zm-2.2 0c0-.92-.2-1.7-.6-2.22-.38-.54-.94-.8-1.64-.8-.72 0-1.27.26-1.67.8-.4.54-.58 1.3-.58 2.22 0 .93.2 1.56.6 2.1.38.54.94.8 1.64.8s1.25-.26 1.65-.8c.4-.55.6-1.17.6-2.1zm6.97 4.7c-3.5.02-3.5-2.8-3.5-3.27L113.57.92l2.15-.34v10c0 .25 0 1.87 1.37 1.88v1.8zm3.77 0h-2.15v-9.2l2.15-.33v9.54zM119.8 3.74c.7 0 1.3-.58 1.3-1.3 0-.7-.58-1.3-1.3-1.3-.73 0-1.3.6-1.3 1.3 0 .72.58 1.3 1.3 1.3zm6.43 1c.7 0 1.3.1 1.78.27.5.18.88.42 1.17.73.28.3.5.74.6 1.18.13.46.2.95.2 1.5v5.47a25.24 25.24 0 0 1-1.5.25c-.67.1-1.42.15-2.25.15a6.83 6.83 0 0 1-1.52-.16 3.2 3.2 0 0 1-1.18-.5 2.46 2.46 0 0 1-.76-.9c-.18-.37-.27-.9-.27-1.44 0-.52.1-.85.3-1.2.2-.37.48-.67.83-.9a3.6 3.6 0 0 1 1.23-.5 7.07 7.07 0 0 1 2.2-.1l.83.16v-.35c0-.25-.03-.48-.1-.7a1.5 1.5 0 0 0-.3-.58c-.15-.18-.34-.3-.58-.4a2.54 2.54 0 0 0-.92-.17c-.5 0-.94.06-1.35.13-.4.08-.75.16-1 .25l-.27-1.74c.27-.1.67-.18 1.2-.28a9.34 9.34 0 0 1 1.65-.14zm.18 7.74c.66 0 1.15-.04 1.5-.1V10.2a5.1 5.1 0 0 0-2-.1c-.23.03-.45.1-.64.2a1.17 1.17 0 0 0-.47.38c-.13.17-.18.26-.18.52 0 .5.17.8.5.98.32.2.74.3 1.3.3zM84.1 4.8c.72 0 1.3.08 1.8.26.48.17.87.42 1.15.73.3.3.5.72.6 1.17.14.45.2.94.2 1.47v5.48a25.24 25.24 0 0 1-1.5.26c-.67.1-1.42.14-2.25.14a6.83 6.83 0 0 1-1.52-.16 3.2 3.2 0 0 1-1.18-.5 2.46 2.46 0 0 1-.76-.9c-.18-.38-.27-.9-.27-1.44 0-.53.1-.86.3-1.22.2-.36.5-.65.84-.88a3.6 3.6 0 0 1 1.24-.5 7.07 7.07 0 0 1 2.2-.1c.26.03.54.08.84.15v-.35c0-.24-.03-.48-.1-.7a1.5 1.5 0 0 0-.3-.58c-.15-.17-.34-.3-.58-.4a2.54 2.54 0 0 0-.9-.15c-.5 0-.96.05-1.37.12-.4.07-.75.15-1 .24l-.26-1.75c.27-.08.67-.17 1.18-.26a8.9 8.9 0 0 1 1.66-.15zm.2 7.73c.65 0 1.14-.04 1.48-.1v-2.17a5.1 5.1 0 0 0-1.98-.1c-.24.03-.46.1-.65.18a1.17 1.17 0 0 0-.47.4c-.12.17-.17.26-.17.52 0 .5.18.8.5.98.32.2.75.3 1.3.3zm8.68 1.74c-3.5 0-3.5-2.82-3.5-3.28L89.45.92 91.6.6v10c0 .25 0 1.87 1.38 1.88v1.8z"/><path fill="%231D3657" d="M5.03 11.03c0 .7-.26 1.24-.76 1.64-.5.4-1.2.6-2.1.6-.88 0-1.6-.14-2.17-.42v-1.2c.36.16.74.3 1.14.38.4.1.78.15 1.13.15.5 0 .88-.1 1.12-.3a.94.94 0 0 0 .35-.77.98.98 0 0 0-.33-.74c-.22-.2-.68-.44-1.37-.72-.72-.3-1.22-.62-1.52-1C.23 8.27.1 7.82.1 7.3c0-.65.22-1.17.7-1.55.46-.37 1.08-.56 1.86-.56.76 0 1.5.16 2.25.48l-.4 1.05c-.7-.3-1.32-.44-1.87-.44-.4 0-.73.08-.94.26a.9.9 0 0 0-.33.72c0 .2.04.38.12.52.08.15.22.3.42.4.2.14.55.3 1.06.52.58.24 1 .47 1.27.67.27.2.47.44.6.7.12.26.18.57.18.92zM9 13.27c-.92 0-1.64-.27-2.16-.8-.52-.55-.78-1.3-.78-2.24 0-.97.24-1.73.72-2.3.5-.54 1.15-.82 2-.82.78 0 1.4.25 1.85.72.46.48.7 1.14.7 1.97v.67H7.35c0 .58.17 1.02.46 1.33.3.3.7.47 1.24.47.36 0 .68-.04.98-.1a5.1 5.1 0 0 0 .98-.33v1.02a3.87 3.87 0 0 1-.94.32 5.72 5.72 0 0 1-1.08.1zm-.22-5.2c-.4 0-.73.12-.97.38s-.37.62-.42 1.1h2.7c0-.48-.13-.85-.36-1.1-.23-.26-.54-.38-.94-.38zm7.7 5.1l-.26-.84h-.05c-.28.36-.57.6-.86.74-.28.13-.65.2-1.1.2-.6 0-1.05-.16-1.38-.48-.32-.32-.5-.77-.5-1.34 0-.62.24-1.08.7-1.4.45-.3 1.14-.47 2.07-.5l1.02-.03V9.2c0-.37-.1-.65-.27-.84-.17-.2-.45-.28-.82-.28-.3 0-.6.04-.88.13a6.68 6.68 0 0 0-.8.33l-.4-.9a4.4 4.4 0 0 1 1.05-.4 4.86 4.86 0 0 1 1.08-.12c.76 0 1.33.18 1.7.5.4.33.6.85.6 1.56v4h-.9zm-1.9-.87c.47 0 .83-.13 1.1-.38.3-.26.43-.62.43-1.08v-.52l-.76.03c-.6.03-1.02.13-1.3.3s-.4.45-.4.82c0 .26.08.47.24.6.16.16.4.23.7.23zm7.57-5.2c.25 0 .46.03.62.06l-.12 1.18a2.38 2.38 0 0 0-.56-.06c-.5 0-.92.16-1.24.5-.3.32-.47.75-.47 1.27v3.1h-1.27V7.23h1l.16 1.05h.05c.2-.36.45-.64.77-.85a1.83 1.83 0 0 1 1.02-.3zm4.12 6.17c-.9 0-1.58-.27-2.05-.8-.47-.52-.7-1.27-.7-2.25 0-1 .24-1.77.73-2.3.5-.54 1.2-.8 2.12-.8.63 0 1.2.1 1.7.34l-.4 1c-.52-.2-.96-.3-1.3-.3-1.04 0-1.55.68-1.55 2.05 0 .67.13 1.17.38 1.5.26.34.64.5 1.13.5a3.23 3.23 0 0 0 1.6-.4v1.1a2.53 2.53 0 0 1-.73.28 4.36 4.36 0 0 1-.93.08zm8.28-.1h-1.27V9.5c0-.45-.1-.8-.28-1.02-.18-.23-.47-.34-.88-.34-.53 0-.9.16-1.16.48-.25.3-.38.85-.38 1.6v2.94h-1.26V4.8h1.26v2.12c0 .34-.02.7-.06 1.1h.08a1.76 1.76 0 0 1 .72-.67c.3-.16.66-.24 1.07-.24 1.43 0 2.15.74 2.15 2.2v3.86zM42.2 7.1c.74 0 1.32.28 1.73.82.4.53.62 1.3.62 2.26 0 .97-.2 1.73-.63 2.27-.42.54-1 .82-1.75.82s-1.33-.27-1.75-.8h-.08l-.23.7h-.94V4.8h1.26v2l-.02.64-.03.56h.05c.4-.6 1-.9 1.78-.9zm-.33 1.04c-.5 0-.88.15-1.1.45-.22.3-.34.8-.35 1.5v.08c0 .72.12 1.24.35 1.57.23.32.6.48 1.12.48.44 0 .78-.17 1-.53.24-.35.36-.87.36-1.53 0-1.35-.47-2.03-1.4-2.03zm3.24-.92h1.4l1.2 3.37c.18.47.3.92.36 1.34h.04l.18-.72 1.37-4H51l-2.53 6.73c-.46 1.23-1.23 1.85-2.3 1.85-.3 0-.56-.03-.83-.1v-1c.2.05.4.08.65.08.6 0 1.03-.36 1.28-1.06l.22-.56-2.4-5.94z"/></g></svg>');background-repeat:no-repeat;background-position:50%;background-size:100%;overflow:hidden;text-indent:-9000px;width:110px;height:100%;display:block;margin-left:auto;margin-right:5px}</style><meta name="generator" content="Gatsby 2.32.13"/><style id="glamor-styles">.css-xbsqlp,[data-css-xbsqlp]{flex:1 0 auto;margin-top:calc(var(--header-height-large) + var(--survey-banner-height-normal) + var(--social-banner-height-normal));-webkit-flex:1 0 auto;}@media (min-width: 780px) and (max-width: 979px){.css-xbsqlp,[data-css-xbsqlp]{margin-top:calc(var(--header-height-normal) + var(--survey-banner-height-normal) + var(--social-banner-height-normal));}}@media (max-width: 599px){.css-xbsqlp,[data-css-xbsqlp]{margin-top:calc(var(--header-height-small) + var(--survey-banner-height-small) + var(--social-banner-height-small));}}.css-190hivd,[data-css-190hivd]{display:-webkit-box; display: -moz-box; display: -ms-flexbox; display: -webkit-flex; display: flex;flex-direction:column;min-height:calc(100vh - 40px);-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;}.css-184keb2,[data-css-184keb2]{color:inherit;margin-left:10px;font-weight:700;font-size:20px;line-height:20px;}@media (max-width: 979px){.css-184keb2,[data-css-184keb2]{font-size:16px;margin-top:1px;}}@media (max-width: 599px){.css-184keb2,[data-css-184keb2]{position:absolute;overflow:hidden;clip:rect(0 0 0 0);height:1px;width:1px;margin:-1px;padding:0;border:0;}}.css-4ivotw,[data-css-4ivotw]{display:-webkit-box; display: -moz-box; display: -ms-flexbox; display: -webkit-flex; display: flex;margin-right:10px;height:100%;align-items:center;color:#61dafb;-webkit-box-align:center;-webkit-align-items:center;}.css-4ivotw:focus,[data-css-4ivotw]:focus{outline:0;color:#ffffff;}@media (min-width: 600px){.css-4ivotw,[data-css-4ivotw]{width:calc(100% / 6);}}@media (max-width: 599px){.css-4ivotw,[data-css-4ivotw]{flex:0 0 auto;-webkit-flex:0 0 auto;}}.css-79txt3,[data-css-79txt3]{flex:1;display:-webkit-box; display: -moz-box; display: -ms-flexbox; display: -webkit-flex; display: flex;flex-direction:row;align-items:stretch;overflow-x:auto;overflow-y:hidden;-webkit-overflow-scrolling:touch;height:100%;scrollbar-width:none;-ms-overflow-style:none;-webkit-flex:1;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;-webkit-box-align:stretch;-webkit-align-items:stretch;}.css-79txt3::-webkit-scrollbar,[data-css-79txt3]::-webkit-scrollbar{display:none;}@media (min-width: 0px) and (max-width: 599px){.css-79txt3,[data-css-79txt3]{flex-grow:1;width:auto;-webkit-flex-grow:1;}}@media (max-width: 599px){.css-79txt3,[data-css-79txt3]{mask-image:-webkit-linear-gradient(to right, transparent, black 20px, black 90%, transparent); mask-image: -moz-linear-gradient(to right, transparent, black 20px, black 90%, transparent); mask-image: linear-gradient(to right, transparent, black 20px, black 90%, transparent);-webkit-mask-image:-webkit-linear-gradient(to right, transparent, black 20px, black 90%, transparent); -webkit-mask-image: -moz-linear-gradient(to right, transparent, black 20px, black 90%, transparent); -webkit-mask-image: linear-gradient(to right, transparent, black 20px, black 90%, transparent);}}.css-zvm479,[data-css-zvm479]{padding:5px 10px;white-space:nowrap;font-size:14px;}.css-zvm479:hover,[data-css-zvm479]:hover{color:#61dafb;}.css-zvm479:focus,[data-css-zvm479]:focus{outline:0;background-color:#373940;border-radius:15px;}@media (max-width: 779px){.css-zvm479,[data-css-zvm479]{display:none;}}.css-1rsw1pf,[data-css-1rsw1pf]{margin-left:0.5rem;}@media (max-width: 779px){.css-1rsw1pf,[data-css-1rsw1pf]{display:none;}}.css-1upvlu3,[data-css-1upvlu3]{display:-webkit-box; display: -moz-box; display: -ms-flexbox; display: -webkit-flex; display: flex;align-items:center;padding:5px 10px;white-space:nowrap;font-size:14px;-webkit-box-align:center;-webkit-align-items:center;}.css-1upvlu3:hover,[data-css-1upvlu3]:hover{color:#61dafb;}.css-1upvlu3:focus,[data-css-1upvlu3]:focus{outline:0;background-color:#373940;border-radius:15px;}.css-6oo1gu,[data-css-6oo1gu]{padding:5px 10px;margin-left:10px;white-space:nowrap;font-size:14px;}.css-6oo1gu:hover,[data-css-6oo1gu]:hover{color:#61dafb;}.css-6oo1gu:focus,[data-css-6oo1gu]:focus{outline:0;background-color:#373940;border-radius:15px;}@media (max-width: 979px){.css-6oo1gu,[data-css-6oo1gu]{display:none;}}.css-nypjs8,[data-css-nypjs8]{display:-webkit-box; display: -moz-box; display: -ms-flexbox; display: -webkit-flex; display: flex;align-items:center;justify-content:flex-end;width:auto;-webkit-box-align:center;-webkit-align-items:center;-webkit-box-pack:end;-webkit-justify-content:flex-end;}.css-heonw3,[data-css-heonw3]{display:-webkit-box; display: -moz-box; display: -ms-flexbox; display: -webkit-flex; display: flex;flex-direction:row;align-items:center;height:var(--header-height-large);-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;-webkit-box-align:center;-webkit-align-items:center;}@media (min-width: 780px) and (max-width: 979px){.css-heonw3,[data-css-heonw3]{height:var(--header-height-normal);}}@media (max-width: 599px){.css-heonw3,[data-css-heonw3]{height:var(--header-height-small);}}.css-19rsoyj,[data-css-19rsoyj]{background-color:#20232a;color:#ffffff;position:fixed;z-index:1;width:100%;top:0;left:0;}@media print{.css-19rsoyj,[data-css-19rsoyj]{display:none;}}.css-1loxuh3,[data-css-1loxuh3]{background-color:hsl(222, 14%, 10%);}.css-tctv7l,[data-css-tctv7l]{padding-left:20px;padding-right:20px;margin-left:auto;margin-right:auto;}@media (min-width: 780px){.css-tctv7l,[data-css-tctv7l]{width:90%;}}@media (min-width: 1340px){.css-tctv7l,[data-css-tctv7l]{max-width:1260px;}}.css-w4tulb,[data-css-w4tulb]{width:auto;height:35px;}.css-t4a06n,[data-css-t4a06n]{display:-webkit-box; display: -moz-box; display: -ms-flexbox; display: -webkit-flex; display: flex;margin-right:1rem;}@media (max-width: 779px){.css-t4a06n,[data-css-t4a06n]{display:none;}}.css-1e8x600,[data-css-1e8x600]{margin-right:0.5rem;}.css-1og5p3u,[data-css-1og5p3u]{color:#61dafb;}.css-15dgx4v,[data-css-15dgx4v]{color:#ddd;transition:color 200ms ease-out;-webkit-transition:color 200ms ease-out;-moz-transition:color 200ms ease-out;}.css-15dgx4v:hover,[data-css-15dgx4v]:hover{color:#ffffff;}.css-lcvzl3,[data-css-lcvzl3]{display:-webkit-box; display: -moz-box; display: -ms-flexbox; display: -webkit-flex; display: flex;}@media (max-width: 599px){.css-lcvzl3,[data-css-lcvzl3]{flex-direction:column;line-height:1.5;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;}}.css-s3feo0,[data-css-s3feo0]{width:10px;height:10px;}.css-w59gkz,[data-css-w59gkz]{background:transparent;padding:0.25rem 0.5rem;border-radius:0.25rem;border:0;background-color:hsl(222, 14%, 30%);color:#ddd;cursor:pointer;transition:color 200ms ease-out;margin-left:2rem;font-size:14px;-webkit-transition:color 200ms ease-out;-moz-transition:color 200ms ease-out;}.css-w59gkz:hover,[data-css-w59gkz]:hover{color:#ffffff;}.css-p5tzjw,[data-css-p5tzjw]{display:-webkit-box; display: -moz-box; display: -ms-flexbox; display: -webkit-flex; display: flex;justify-content:flex-end;flex-grow:1;-webkit-box-pack:end;-webkit-justify-content:flex-end;-webkit-flex-grow:1;}.css-lpiycv,[data-css-lpiycv]{display:-webkit-box; display: -moz-box; display: -ms-flexbox; display: -webkit-flex; display: flex;justify-content:center;align-items:center;height:100%;-webkit-box-pack:center;-webkit-justify-content:center;-webkit-box-align:center;-webkit-align-items:center;}.css-ebdw9u,[data-css-ebdw9u]{display:var(--survey-banner-display);height:var(--survey-banner-height-normal);font-size:18px;}@media (max-width: 979px){.css-ebdw9u,[data-css-ebdw9u]{font-size:16px;}}@media (max-width: 599px){.css-ebdw9u,[data-css-ebdw9u]{height:var(--survey-banner-height-small);font-size:14px;}}.css-1ookbab,[data-css-1ookbab]{vertical-align:-2px;display:inline-block;margin-left:0.5rem;color:inherit;}.css-714dwk,[data-css-714dwk]{display:-webkit-box; display: -moz-box; display: -ms-flexbox; display: -webkit-flex; display: flex;}@media (max-width: 599px){.css-714dwk,[data-css-714dwk]{flex-direction:column;line-height:1.5;text-align:center;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;}}.css-1hu70yk,[data-css-1hu70yk]{display:var(--social-banner-display);height:var(--social-banner-height-normal);font-size:18px;font-weight:bold;}@media (max-width: 979px){.css-1hu70yk,[data-css-1hu70yk]{font-size:16px;}}@media (max-width: 599px){.css-1hu70yk,[data-css-1hu70yk]{height:var(--social-banner-height-small);font-size:14px;}}.css-hobwqm,[data-css-hobwqm]{display:-webkit-box; display: -moz-box; display: -ms-flexbox; display: -webkit-flex; display: flex;flex-direction:row;align-items:center;color:#ffffff;transition:color 0.2s ease-out;padding-left:15px;padding-right:15px;font-weight:300;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;-webkit-box-align:center;-webkit-align-items:center;-webkit-transition:color 0.2s ease-out;-moz-transition:color 0.2s ease-out;}.css-hobwqm:focus,[data-css-hobwqm]:focus{outline:0;background-color:#373940;color:#ffffff;}@media (min-width: 0px) and (max-width: 599px){.css-hobwqm,[data-css-hobwqm]{padding-left:8px;padding-right:8px;}}@media (min-width: 600px) and (max-width: 979px){.css-hobwqm,[data-css-hobwqm]{padding-left:10px;padding-right:10px;}}@media (min-width: 1280px){.css-hobwqm,[data-css-hobwqm]{padding-left:20px;padding-right:20px;font-size:18px;}.css-hobwqm:hover:not(:focus),[data-css-hobwqm]:hover:not(:focus){color:#61dafb;}}.css-7dpbpx,[data-css-7dpbpx]{width:100%;appearance:none;background:transparent;border:0;color:#ffffff;font-size:18px;font-weight:300;font-family:inherit;position:relative;padding:4px 4px 4px 29px;background-image:url(/search.svg);background-size:16px 16px;background-repeat:no-repeat;background-position-y:center;background-position-x:4px;-webkit-appearance:none;-moz-appearance:none;}.css-7dpbpx:focus,[data-css-7dpbpx]:focus{outline:0;background-color:#373940;border-radius:0.25rem;}@media (max-width: 1179px){.css-7dpbpx,[data-css-7dpbpx]{font-size:16px;width:16px;transition:width 0.2s ease, padding 0.2s ease;padding-left:16px;-webkit-transition:width 0.2s ease, padding 0.2s ease;-moz-transition:width 0.2s ease, padding 0.2s ease;}.css-7dpbpx:focus,[data-css-7dpbpx]:focus{padding-left:29px;width:8rem;outline:none;}}.css-7vmqep,[data-css-7vmqep]{display:-webkit-box; display: -moz-box; display: -ms-flexbox; display: -webkit-flex; display: flex;flex:0 0 auto;flex-direction:row;align-items:center;padding-left:0.25rem;padding-right:0.25rem;-webkit-flex:0 0 auto;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;-webkit-box-align:center;-webkit-align-items:center;}@media (max-width: 1179px){.css-7vmqep,[data-css-7vmqep]{justify-content:flex-end;margin-right:10px;-webkit-box-pack:end;-webkit-justify-content:flex-end;}}@media (min-width: 1180px){.css-7vmqep,[data-css-7vmqep]{min-width:100px;width:calc(100% / 5);}}.css-c4d79v,[data-css-c4d79v]{fill:currentColor;}.css-1yyhkcy,[data-css-1yyhkcy]{margin-left:5px;vertical-align:-2px;color:#6B6B6B;}.css-15lkjjo,[data-css-15lkjjo]{display:-webkit-box; display: -moz-box; display: -ms-flexbox; display: -webkit-flex; display: flex;flex-direction:column;flex-grow:1;flex-shrink:0;flex-basis:auto;justify-content:stretch;align-items:flex-start;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;-webkit-flex-grow:1;-webkit-flex-shrink:0;-webkit-flex-basis:auto;-webkit-box-pack:stretch;-webkit-justify-content:stretch;-webkit-box-align:start;-webkit-align-items:flex-start;}.css-1q9mcvr,[data-css-1q9mcvr]{flex-wrap:wrap;display:-webkit-box; display: -moz-box; display: -ms-flexbox; display: -webkit-flex; display: flex;-webkit-box-lines:multiple;-webkit-flex-wrap:wrap;}@media (max-width: 979px){.css-1q9mcvr,[data-css-1q9mcvr]{width:100%;}}@media (min-width: 1280px){.css-1q9mcvr,[data-css-1q9mcvr]{width:calc(100% / 3 * 2);padding-left:40px;}}.css-1izr7si,[data-css-1izr7si]{max-width:160px;height:auto;}.css-1yy5aal,[data-css-1yy5aal]{color:#999;padding-top:15px;}.css-vn0yrr,[data-css-vn0yrr]{background-color:#20232a;color:#ffffff;padding-top:10px;padding-bottom:50px;}@media (min-width: 2000px){.css-vn0yrr,[data-css-vn0yrr]{padding-top:40px;}}@media print{.css-vn0yrr,[data-css-vn0yrr]{display:none;}}.css-1m3wp4q,[data-css-1m3wp4q]{display:-webkit-inline-box; display: -moz-inline-box; display: -ms-inline-flexbox; display: -webkit-inline-flex; display: inline-flex;flex-direction:column;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;}.css-12bsqfj,[data-css-12bsqfj]{display:-webkit-box; display: -moz-box; display: -ms-flexbox; display: -webkit-flex; display: flex;flex-direction:column;align-items:flex-start;width:50%;padding-top:40px;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;-webkit-box-align:start;-webkit-align-items:flex-start;}@media (min-width: 2000px){.css-12bsqfj,[data-css-12bsqfj]{padding-top:0;width:25%;}}.css-krwajx,[data-css-krwajx]{color:#999;font-size:14px;font-weight:700;line-height:3;text-transform:uppercase;text-align:start;letter-spacing:0.08em;}.css-8l81zy,[data-css-8l81zy]{line-height:2;}.css-8l81zy:hover,[data-css-8l81zy]:hover{color:#61dafb;}.css-6na5q4,[data-css-6na5q4]{vertical-align:-2px;display:inline-block;margin-left:5px;color:#6B6B6B;}@media (min-width: 600px){.css-2y24fj,[data-css-2y24fj]{position:absolute;bottom:-1px;height:4px;background:#61dafb;left:0;right:0;z-index:1;}}.css-li68ai,[data-css-li68ai]{display:-webkit-box; display: -moz-box; display: -ms-flexbox; display: -webkit-flex; display: flex;flex-direction:row;align-items:center;color:#61dafb;transition:color 0.2s ease-out;padding-left:15px;padding-right:15px;font-weight:300;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;-webkit-box-align:center;-webkit-align-items:center;-webkit-transition:color 0.2s ease-out;-moz-transition:color 0.2s ease-out;}.css-li68ai:focus,[data-css-li68ai]:focus{outline:0;background-color:#373940;color:#ffffff;}@media (min-width: 0px) and (max-width: 599px){.css-li68ai,[data-css-li68ai]{padding-left:8px;padding-right:8px;}}@media (min-width: 600px) and (max-width: 979px){.css-li68ai,[data-css-li68ai]{padding-left:10px;padding-right:10px;}}@media (min-width: 1280px){.css-li68ai,[data-css-li68ai]{padding-left:20px;padding-right:20px;font-size:18px;}.css-li68ai:hover:not(:focus),[data-css-li68ai]:hover:not(:focus){color:#61dafb;}}@media (min-width: 600px){.css-li68ai,[data-css-li68ai]{position:relative;}}.css-6nf64v,[data-css-6nf64v]{line-height:25px;}.css-6nf64v .gatsby-highlight,[data-css-6nf64v] .gatsby-highlight{margin-top:25px;margin-left:-30px;margin-right:-30px;margin-bottom:25px;padding-left:15px;padding-right:15px;}.css-6nf64v a:not(.anchor):not(.gatsby-resp-image-link),[data-css-6nf64v] a:not(.anchor):not(.gatsby-resp-image-link){background-color:rgba(187,239,253,0.3);border-bottom:1px solid rgba(0,0,0,0.2);color:#1a1a1a;}.css-6nf64v a:not(.anchor):not(.gatsby-resp-image-link):hover,[data-css-6nf64v] a:not(.anchor):not(.gatsby-resp-image-link):hover{background-color:#bbeffd;border-bottom-color:#1a1a1a;}.css-6nf64v > p:first-child,[data-css-6nf64v] > p:first-child{font-size:18px;font-weight:300;color:#6B6B6B;}.css-6nf64v > p:first-child a,[data-css-6nf64v] > p:first-child a, .css-6nf64v > p:first-child strong, [data-css-6nf64v] > p:first-child strong{font-weight:400;}.css-6nf64v p,[data-css-6nf64v] p{margin-top:30px;font-size:17px;line-height:1.7;max-width:42em;}.css-6nf64v p:first-of-type,[data-css-6nf64v] p:first-of-type{margin-top:15px;}.css-6nf64v p:first-child,[data-css-6nf64v] p:first-child{margin-top:0;}.css-6nf64v h3 + p,[data-css-6nf64v] h3 + p, .css-6nf64v h3 + p:first-of-type, [data-css-6nf64v] h3 + p:first-of-type{margin-top:20px;}.css-6nf64v p > code,[data-css-6nf64v] p > code, .css-6nf64v li > code, [data-css-6nf64v] li > code{background:rgba(255,229,100,0.2);color:#1a1a1a;}.css-6nf64v p > code,[data-css-6nf64v] p > code, .css-6nf64v li > code, [data-css-6nf64v] li > code, .css-6nf64v p > a > code, [data-css-6nf64v] p > a > code, .css-6nf64v li > a > code, [data-css-6nf64v] li > a > code{padding:0 3px;font-size:0.94em;word-break:break-word;}.css-6nf64v hr,[data-css-6nf64v] hr{height:1px;margin-bottom:-1px;border:none;border-bottom:1px solid #ececec;margin-top:40px;}.css-6nf64v hr:first-child,[data-css-6nf64v] hr:first-child{margin-top:0;}.css-6nf64v h1,[data-css-6nf64v] h1{line-height:1.2;}.css-6nf64v h2::before,[data-css-6nf64v] h2::before{content:" ";display:block;border-bottom:1px solid #ececec;padding-top:44px;margin-bottom:40px;}.css-6nf64v h2,[data-css-6nf64v] h2{line-height:1.2;}.css-6nf64v h2:first-child::before,[data-css-6nf64v] h2:first-child::before{content:" ";display:block;border-bottom:0;padding-top:40px;margin-top:-80px;}.css-6nf64v hr + h2,[data-css-6nf64v] hr + h2{border-top:0;margin-top:0;}.css-6nf64v h3::before,[data-css-6nf64v] h3::before{content:" ";display:block;padding-top:90px;margin-top:-45px;}.css-6nf64v h2 + h3::before,[data-css-6nf64v] h2 + h3::before, .css-6nf64v h2 + h3:first-of-type::before, [data-css-6nf64v] h2 + h3:first-of-type::before{content:" ";display:block;padding-top:60px;margin-top:-30px;}.css-6nf64v h4::before,[data-css-6nf64v] h4::before{content:" ";display:block;padding-top:100px;margin-top:-50px;}.css-6nf64v h4,[data-css-6nf64v] h4{font-size:20px;color:#6B6B6B;line-height:1.3;font-weight:400;}.css-6nf64v h4 + p,[data-css-6nf64v] h4 + p{margin-top:20px;}.css-6nf64v ol,[data-css-6nf64v] ol, .css-6nf64v ul, [data-css-6nf64v] ul{margin-top:20px;font-size:16px;color:#1a1a1a;padding-left:20px;}.css-6nf64v ol p,[data-css-6nf64v] ol p, .css-6nf64v ul p, [data-css-6nf64v] ul p, .css-6nf64v ol p:first-of-type, [data-css-6nf64v] ol p:first-of-type, .css-6nf64v ul p:first-of-type, [data-css-6nf64v] ul p:first-of-type{font-size:16px;margin-top:0;line-height:1.2;}.css-6nf64v ol li,[data-css-6nf64v] ol li, .css-6nf64v ul li, [data-css-6nf64v] ul li{margin-top:10px;}.css-6nf64v ol li.button-newapp,[data-css-6nf64v] ol li.button-newapp, .css-6nf64v ul li.button-newapp, [data-css-6nf64v] ul li.button-newapp{margin-top:0;}.css-6nf64v ol ol,[data-css-6nf64v] ol ol, .css-6nf64v ul ol, [data-css-6nf64v] ul ol, .css-6nf64v ol ul, [data-css-6nf64v] ol ul, .css-6nf64v ul ul, [data-css-6nf64v] ul ul{margin-left:20px;margin-top:10px;}.css-6nf64v img,[data-css-6nf64v] img{max-width:100%;}.css-6nf64v ol,[data-css-6nf64v] ol{list-style:decimal;}.css-6nf64v ul,[data-css-6nf64v] ul{list-style:disc;}.css-6nf64v blockquote,[data-css-6nf64v] blockquote{background-color:rgba(255,229,100,0.3);border-left-color:#ffe564;border-left-width:9px;border-left-style:solid;padding:20px 45px 20px 26px;margin-bottom:30px;margin-top:20px;margin-left:-30px;margin-right:-30px;}.css-6nf64v blockquote p,[data-css-6nf64v] blockquote p{margin-top:15px;}.css-6nf64v blockquote p:first-of-type,[data-css-6nf64v] blockquote p:first-of-type{font-weight:700;margin-top:0;}.css-6nf64v blockquote p:nth-of-type(2),[data-css-6nf64v] blockquote p:nth-of-type(2){margin-top:0;}.css-6nf64v blockquote .gatsby-highlight,[data-css-6nf64v] blockquote .gatsby-highlight{margin-left:0;}.css-6nf64v .gatsby-highlight + blockquote,[data-css-6nf64v] .gatsby-highlight + blockquote{margin-top:40px;}.css-6nf64v .gatsby-highlight + h4::before,[data-css-6nf64v] .gatsby-highlight + h4::before{content:" ";display:block;padding-top:85px;margin-top:-60px;}@media (max-width: 599px){.css-6nf64v .gatsby-highlight,[data-css-6nf64v] .gatsby-highlight{margin-left:-20px;margin-right:-20px;border-radius:0;}.css-6nf64v h3,[data-css-6nf64v] h3{overflow-wrap:break-word;word-break:break-word;}.css-6nf64v blockquote,[data-css-6nf64v] blockquote{margin-left:-20px;margin-right:-20px;}}@media (min-width: 1280px){.css-6nf64v > p:first-child,[data-css-6nf64v] > p:first-child{font-size:24px;}.css-6nf64v h1,[data-css-6nf64v] h1{font-size:60px;}.css-6nf64v h2,[data-css-6nf64v] h2{font-size:35px;}.css-6nf64v h3,[data-css-6nf64v] h3{font-size:25px;line-height:1.3;}}@media (max-width: 979px){.css-6nf64v p,[data-css-6nf64v] p{font-size:16px;margin-top:25px;}.css-6nf64v h2,[data-css-6nf64v] h2{font-size:20px;}}@media (min-width: 0px) and (max-width: 599px){.css-6nf64v h1,[data-css-6nf64v] h1{font-size:30px;}}@media (min-width: 600px) and (max-width: 1279px){.css-6nf64v h1,[data-css-6nf64v] h1{font-size:45px;}}.css-11xil2b,[data-css-11xil2b]{white-space:nowrap;padding-bottom:1em;margin-right:36px;display:inline-block;color:#6B6B6B;}.css-1epz0fh,[data-css-1epz0fh]{color:#373940;border-color:#ececec;transition:color 0.2s ease, border-color 0.2s ease;white-space:nowrap;border-bottom-width:1px;border-bottom-style:solid;-webkit-transition:color 0.2s ease, border-color 0.2s ease;-moz-transition:color 0.2s ease, border-color 0.2s ease;}.css-1epz0fh:hover,[data-css-1epz0fh]:hover{color:#1a1a1a;border-color:#1a1a1a;}.css-1epz0fh:focus,[data-css-1epz0fh]:focus{color:#1a1a1a;border-color:#1a1a1a;}.css-1m173d1,[data-css-1m173d1]{margin-top:80px;}.css-124oy3v,[data-css-124oy3v]{margin-top:40px;margin-bottom:120px;}@media (min-width: 780px){.css-124oy3v,[data-css-124oy3v]{margin-top:50px;}}.css-1kbu8hg,[data-css-1kbu8hg]{display:-webkit-box; display: -moz-box; display: -ms-flexbox; display: -webkit-flex; display: flex;flex-direction:column;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;}@media (min-width: 600px){.css-1kbu8hg,[data-css-1kbu8hg]{border-left:1px solid #ececec;margin-left:80px;}}@media (min-width: 600px) and (max-width: 1339px){.css-1kbu8hg,[data-css-1kbu8hg]{flex:0 0 200px;margin-left:80px;-webkit-flex:0 0 200px;}}@media (min-width: 600px) and (max-width: 979px){.css-1kbu8hg,[data-css-1kbu8hg]{margin-left:40px;}}@media (min-width: 1100px){.css-1kbu8hg,[data-css-1kbu8hg]{flex:0 0 300px;-webkit-flex:0 0 300px;}}@media (min-width: 2000px){.css-1kbu8hg,[data-css-1kbu8hg]{position:fixed;right:0;width:300px;z-index:2;}}.css-10335ra,[data-css-10335ra]{display:-webkit-box; display: -moz-box; display: -ms-flexbox; display: -webkit-flex; display: flex;min-height:calc(100vh - 60px);}@media (min-width: 2000px){.css-10335ra,[data-css-10335ra]{max-width:840px;margin-left:auto;margin-right:auto;}}@media (max-width: 599px){.css-10335ra,[data-css-10335ra]{flex-direction:column;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;}}.css-12vsfho,[data-css-12vsfho]{flex:1 0 auto;-webkit-flex:1 0 auto;}.css-1m1176,[data-css-1m1176]{width:100%;flex:1 0 auto;position:relative;z-index:0;-webkit-flex:1 0 auto;}.css-1m1176 h1,[data-css-1m1176] h1, .css-1m1176 h2, [data-css-1m1176] h2, .css-1m1176 h3, [data-css-1m1176] h3, .css-1m1176 h4, [data-css-1m1176] h4, .css-1m1176 h5, [data-css-1m1176] h5, .css-1m1176 h6, [data-css-1m1176] h6{scroll-margin-top:60px;}@media (max-width: 779px){.css-1m1176 h1,[data-css-1m1176] h1, .css-1m1176 h2, [data-css-1m1176] h2, .css-1m1176 h3, [data-css-1m1176] h3, .css-1m1176 h4, [data-css-1m1176] h4, .css-1m1176 h5, [data-css-1m1176] h5, .css-1m1176 h6, [data-css-1m1176] h6{scroll-margin-top:40px;}}.css-95xunl,[data-css-95xunl]{display:-webkit-box; display: -moz-box; display: -ms-flexbox; display: -webkit-flex; display: flex;flex-direction:column;flex-grow:1;flex-shrink:0;flex-basis:auto;justify-content:flex-start;align-items:stretch;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;-webkit-flex-grow:1;-webkit-flex-shrink:0;-webkit-flex-basis:auto;-webkit-box-pack:start;-webkit-justify-content:flex-start;-webkit-box-align:stretch;-webkit-align-items:stretch;}.css-174qq1k,[data-css-174qq1k]{display:-webkit-box; display: -moz-box; display: -ms-flexbox; display: -webkit-flex; display: flex;flex-direction:column;flex-grow:1;flex-shrink:1;flex-basis:auto;justify-content:flex-start;align-items:stretch;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;-webkit-flex-grow:1;-webkit-flex-shrink:1;-webkit-flex-basis:auto;-webkit-box-pack:start;-webkit-justify-content:flex-start;-webkit-box-align:stretch;-webkit-align-items:stretch;}.css-1obw60b,[data-css-1obw60b]{color:#282c34;margin-bottom:0;margin-top:80px;font-size:60px;line-height:65px;font-weight:700;}@media (max-width: 599px){.css-1obw60b,[data-css-1obw60b]{margin-top:40px;}}@media (max-width: 779px){.css-1obw60b,[data-css-1obw60b]{font-size:40px;line-height:45px;}}@media (min-width: 780px) and (max-width: 979px){.css-1obw60b,[data-css-1obw60b]{margin-top:60px;}}.css-hgc6lu,[data-css-hgc6lu]{display:-webkit-box; display: -moz-box; display: -ms-flexbox; display: -webkit-flex; display: flex;flex-direction:row;flex-grow:0;flex-shrink:1;flex-basis:auto;justify-content:space-between;align-items:baseline;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;-webkit-flex-grow:0;-webkit-flex-shrink:1;-webkit-flex-basis:auto;-webkit-box-pack:justify;-webkit-justify-content:space-between;-webkit-box-align:baseline;-webkit-align-items:baseline;}.css-15scox9,[data-css-15scox9]{transform:translateY(0.1em);-webkit-transform:translateY(0.1em);}.css-1k9fay3,[data-css-1k9fay3]{border:0;background:none;cursor:pointer;margin-left:6px;}.css-1k9fay3:focus,[data-css-1k9fay3]:focus{color:#1a1a1a;border-color:#1a1a1a;}.css-1k9fay3:focus svg,[data-css-1k9fay3]:focus svg{fill:#1a1a1a;}.css-1k9fay3:hover,[data-css-1k9fay3]:hover{color:#1a1a1a;border-color:#1a1a1a;}.css-1k9fay3:hover svg,[data-css-1k9fay3]:hover svg{fill:#1a1a1a;}.css-1k9fay3 svg,[data-css-1k9fay3] svg{height:1.5em;width:1.5em;fill:#6B6B6B;transition:fill 0.2s ease;-webkit-transition:fill 0.2s ease;-moz-transition:fill 0.2s ease;}.css-shr7pv,[data-css-shr7pv]{transform:scale(-1, -1) translateY(-.6em);-webkit-transform:scale(-1, -1) translateY(-.6em);}.css-1s9d23n,[data-css-1s9d23n]{border:0;background:none;cursor:pointer;margin-left:3px;}.css-1s9d23n:focus,[data-css-1s9d23n]:focus{color:#1a1a1a;border-color:#1a1a1a;}.css-1s9d23n:focus svg,[data-css-1s9d23n]:focus svg{fill:#1a1a1a;}.css-1s9d23n:hover,[data-css-1s9d23n]:hover{color:#1a1a1a;border-color:#1a1a1a;}.css-1s9d23n:hover svg,[data-css-1s9d23n]:hover svg{fill:#1a1a1a;}.css-1s9d23n svg,[data-css-1s9d23n] svg{height:1.5em;width:1.5em;fill:#6B6B6B;transition:fill 0.2s ease;-webkit-transition:fill 0.2s ease;-moz-transition:fill 0.2s ease;}.css-dnl0w7,[data-css-dnl0w7]{margin-top:60px;}@media (min-width: 0px) and (max-width: 599px){.css-dnl0w7,[data-css-dnl0w7]{margin-top:40px;}}@media (min-width: 600px) and (max-width: 979px){.css-dnl0w7,[data-css-dnl0w7]{margin-top:20px;}}@media (min-width: 780px) and (max-width: 1279px){.css-dnl0w7,[data-css-dnl0w7]{margin-top:50px;}}@media (min-width: 600px){.css-dnl0w7,[data-css-dnl0w7]{transform:none !important;-webkit-transform:none !important;}}@media (max-width: 599px){.css-1gf3j5r,[data-css-1gf3j5r]{top:calc(var(--survey-banner-height-small) + var(--social-banner-height-small));left:0;bottom:0;right:0;position:fixed;background-color:#ffffff;z-index:2;height:100vh;overflow-y:auto;-webkit-overflow-scrolling:touch;pointer-events:none;}}@media (min-width: 780px){.css-1gf3j5r,[data-css-1gf3j5r]{margin-right:-999px;padding-right:999px;background-color:#f7f7f7;}}@media (min-width: 780px) and (max-width: 1999px){.css-1gf3j5r,[data-css-1gf3j5r]{position:fixed;z-index:2;height:100%;}}@media (min-width: 600px){.css-1gf3j5r,[data-css-1gf3j5r]{position:fixed;z-index:2;height:calc(100vh - 60px);overflow-y:auto;-webkit-overflow-scrolling:touch;margin-right:-999px;padding-right:999px;background-color:#f7f7f7;opacity:1 !important;}}@media (min-width: 600px) and (max-width: 779px){.css-1gf3j5r,[data-css-1gf3j5r]{height:calc(100vh - 40px);}}@media (min-width: 780px) and (max-width: 1279px){.css-1gf3j5r,[data-css-1gf3j5r]{height:calc(100vh - 50px);}}@media (min-width: 2000px){.css-1gf3j5r,[data-css-1gf3j5r]{border-left:1px solid #ececec;}}.css-1dgtft4,[data-css-1dgtft4]{width:20px;height:20px;align-self:center;display:-webkit-box; display: -moz-box; display: -ms-flexbox; display: -webkit-flex; display: flex;flex-direction:column;color:#61dafb;-webkit-align-self:center;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;}.css-7ef8f8,[data-css-7ef8f8]{display:-webkit-box; display: -moz-box; display: -ms-flexbox; display: -webkit-flex; display: flex;flex-direction:row;align-items:center;height:60px;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;-webkit-box-align:center;-webkit-align-items:center;}@media (min-width: 780px) and (max-width: 1279px){.css-7ef8f8,[data-css-7ef8f8]{height:50px;}}@media (max-width: 599px){.css-7ef8f8,[data-css-7ef8f8]{height:60px;overflow:hidden;align-items:flex-start;-webkit-box-align:start;-webkit-align-items:flex-start;}}.css-yx40kw,[data-css-yx40kw]{background-color:#20232a;bottom:44px;color:#61dafb;display:none;cursor:pointer;position:fixed;right:20px;z-index:3;border-radius:50%;border:1px solid rgba(255, 255, 255, 0.1);box-shadow:0 0 20px rgba(0, 0, 0, 0.3);}@media (max-width: 599px){.css-yx40kw,[data-css-yx40kw]{display:inline-block;}}.css-7stz2q,[data-css-7stz2q]{width:100%;padding-left:20px;position:relative;}@media (min-width: 1100px){.css-7stz2q,[data-css-7stz2q]{padding-left:40px;}}@media (max-width: 599px){.css-7stz2q,[data-css-7stz2q]{padding-bottom:100px;}}.css-1aai96l,[data-css-1aai96l]{display:-webkit-box; display: -moz-box; display: -ms-flexbox; display: -webkit-flex; display: flex;flex-direction:column;flex-grow:0;flex-shrink:1;flex-basis:auto;justify-content:flex-start;align-items:stretch;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;-webkit-flex-grow:0;-webkit-flex-shrink:1;-webkit-flex-basis:auto;-webkit-box-pack:start;-webkit-justify-content:flex-start;-webkit-box-align:stretch;-webkit-align-items:stretch;}.css-1j8jxus,[data-css-1j8jxus]{cursor:pointer;background-color:transparent;border:0;margin-top:10px;}.css-e8rm5m,[data-css-e8rm5m]{color:#1a1a1a;display:inline-block;border-bottom:1px solid transparent;transition:border 0.2s ease;margin-top:5px;-webkit-transition:border 0.2s ease;-moz-transition:border 0.2s ease;}.css-e8rm5m:hover,[data-css-e8rm5m]:hover{color:#6B6B6B;}.css-atv6j6,[data-css-atv6j6]{margin-top:5px;}.css-ts0qly,[data-css-ts0qly]{font-feature-settings:'tnum';margin-bottom:10px;-webkit-font-feature-settings:'tnum';}@media (min-width: 600px){.css-ts0qly,[data-css-ts0qly]{display:block;}}.css-1luyeat,[data-css-1luyeat]{color:#6B6B6B;font-size:14px;font-weight:700;line-height:3;text-transform:uppercase;text-align:start;letter-spacing:0.08em;}@media (min-width: 600px){.css-1luyeat,[data-css-1luyeat]{color:#1a1a1a;padding-right:7px;padding-left:7px;}.css-1luyeat:hover,[data-css-1luyeat]:hover{color:#1a1a1a;}}.css-1mwek35,[data-css-1mwek35]{margin-left:7px;transform:rotateX(180deg);transition:-webkit-transform 0.2s ease,transform 0.2s ease;-webkit-transform:rotateX(180deg);-webkit-transition:-webkit-transform 0.2s ease,transform 0.2s ease;-moz-transition:transform 0.2s ease;}@media (max-width: 599px){.css-1mwek35,[data-css-1mwek35]{display:none;}}.css-sg9l1i,[data-css-sg9l1i]{transform:translate(2px, -4px) rotate(180deg);transition:-webkit-transform 0.2s ease,transform 0.2s ease;-webkit-transform:translate(2px, -4px) rotate(180deg);-webkit-transition:-webkit-transform 0.2s ease,transform 0.2s ease;-moz-transition:transform 0.2s ease;}.css-o1zbu3,[data-css-o1zbu3]{transform:translate(2px, 4px);transition:-webkit-transform 0.2s ease,transform 0.2s ease;-webkit-transform:translate(2px, 4px);-webkit-transition:-webkit-transform 0.2s ease,transform 0.2s ease;-moz-transition:transform 0.2s ease;}.css-1ac8j74,[data-css-1ac8j74]{padding-top:40px;display:block !important;}@media (min-width: 1280px){.css-1ac8j74,[data-css-1ac8j74]{width:calc(100% / 3);order:-1;-webkit-order:-1;}}@media (min-width: 980px){.css-1ac8j74,[data-css-1ac8j74]{order:-1;-webkit-order:-1;}}@media (max-width: 979px){.css-1ac8j74,[data-css-1ac8j74]{text-align:center;width:100%;padding-top:40px;}}.css-ftk3jl,[data-css-ftk3jl]{display:-webkit-box; display: -moz-box; display: -ms-flexbox; display: -webkit-flex; display: flex;flex-direction:row;flex-wrap:wrap;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;-webkit-box-lines:multiple;-webkit-flex-wrap:wrap;}@media (min-width: 600px) and (max-width: 979px){.css-ftk3jl,[data-css-ftk3jl]{padding-right:240px;}}@media (min-width: 980px) and (max-width: 1339px){.css-ftk3jl,[data-css-ftk3jl]{padding-right:280px;}}@media (min-width: 1100px) and (max-width: 1999px){.css-ftk3jl,[data-css-ftk3jl]{padding-right:380px;}}.css-ifgy4z,[data-css-ifgy4z]{width:4px;height:25px;border-left:4px solid #61dafb;padding-left:16px;position:absolute;left:0;margin-top:-3px;}@media (min-width: 1100px){.css-ifgy4z,[data-css-ifgy4z]{left:15px;}}.css-1xy1fx4,[data-css-1xy1fx4]{color:#1a1a1a;display:inline-block;border-bottom:1px solid transparent;transition:border 0.2s ease;margin-top:5px;font-weight:700;-webkit-transition:border 0.2s ease;-moz-transition:border 0.2s ease;}.css-1xy1fx4:hover,[data-css-1xy1fx4]:hover{color:#6B6B6B;}.css-14d3mgr,[data-css-14d3mgr]{font-feature-settings:'tnum';margin-bottom:10px;-webkit-font-feature-settings:'tnum';}@media (min-width: 600px){.css-14d3mgr,[data-css-14d3mgr]{display:none;}}.css-hg8mt2,[data-css-hg8mt2]{color:#6B6B6B;font-size:14px;font-weight:700;line-height:3;text-transform:uppercase;text-align:start;letter-spacing:0.08em;}@media (min-width: 600px){.css-hg8mt2,[data-css-hg8mt2]{color:#6B6B6B;padding-right:7px;padding-left:7px;}.css-hg8mt2:hover,[data-css-hg8mt2]:hover{color:#1a1a1a;}}.css-1jiuhrf,[data-css-1jiuhrf]{margin-left:7px;transform:rotateX(0deg);transition:-webkit-transform 0.2s ease,transform 0.2s ease;-webkit-transform:rotateX(0deg);-webkit-transition:-webkit-transform 0.2s ease,transform 0.2s ease;-moz-transition:transform 0.2s ease;}@media (max-width: 599px){.css-1jiuhrf,[data-css-1jiuhrf]{display:none;}}.css-140tz9x,[data-css-140tz9x]{margin-left:20px;}.css-1gz2d9j,[data-css-1gz2d9j]{padding-top:10px;}.css-syjz65,[data-css-syjz65]{text-align:right;}@media (min-width: 600px) and (max-width: 979px){.css-15o825x,[data-css-15o825x]{padding-right:240px;}}@media (min-width: 980px) and (max-width: 1339px){.css-15o825x,[data-css-15o825x]{padding-right:280px;}}@media (min-width: 1100px) and (max-width: 1999px){.css-15o825x,[data-css-15o825x]{padding-right:380px;}}.css-uygc5k,[data-css-uygc5k]{background:#282c34;color:#ffffff;padding-top:50px;padding-bottom:50px;}.css-lhap5,[data-css-lhap5]{display:-webkit-box; display: -moz-box; display: -ms-flexbox; display: -webkit-flex; display: flex;flex-direction:row;flex-grow:0;flex-shrink:1;flex-basis:auto;justify-content:space-between;align-items:flex-start;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;-webkit-flex-grow:0;-webkit-flex-shrink:1;-webkit-flex-basis:auto;-webkit-box-pack:justify;-webkit-justify-content:space-between;-webkit-box-align:start;-webkit-align-items:flex-start;}.css-k2v7we,[data-css-k2v7we]{display:-webkit-box; display: -moz-box; display: -ms-flexbox; display: -webkit-flex; display: flex;flex-direction:row;flex-grow:0;flex-shrink:1;flex-basis:50%;justify-content:flex-start;align-items:flex-start;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;-webkit-flex-grow:0;-webkit-flex-shrink:1;-webkit-flex-basis:50%;-webkit-box-pack:start;-webkit-justify-content:flex-start;-webkit-box-align:start;-webkit-align-items:flex-start;}.css-i3b7x6,[data-css-i3b7x6]{color:#61dafb;font-size:14px;}.css-uhcemv,[data-css-uhcemv]{display:inline;border-color:#6B6B6B;transition:border-color 0.2s ease;font-size:30px;border-bottom-width:1px;border-bottom-style:solid;-webkit-transition:border-color 0.2s ease;-moz-transition:border-color 0.2s ease;}.css-uhcemv:hover,[data-css-uhcemv]:hover{border-color:#ffffff;}@media (max-width: 979px){.css-uhcemv,[data-css-uhcemv]{font-size:24px;}}@media (min-width: 0px) and (max-width: 599px){.css-uhcemv,[data-css-uhcemv]{font-size:16px;}}.css-14qyarc,[data-css-14qyarc]{display:-webkit-box; display: -moz-box; display: -ms-flexbox; display: -webkit-flex; display: flex;flex-direction:row;flex-grow:0;flex-shrink:1;flex-basis:50%;justify-content:flex-end;align-items:flex-start;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;-webkit-flex-grow:0;-webkit-flex-shrink:1;-webkit-flex-basis:50%;-webkit-box-pack:end;-webkit-justify-content:flex-end;-webkit-box-align:start;-webkit-align-items:flex-start;}</style><script id="glamor-ids"> // <![CDATA[ window._glamor = ["xbsqlp","190hivd","184keb2","4ivotw","79txt3","zvm479","1rsw1pf","1upvlu3","6oo1gu","nypjs8","heonw3","19rsoyj","1loxuh3","tctv7l","w4tulb","t4a06n","1e8x600","1og5p3u","15dgx4v","lcvzl3","s3feo0","w59gkz","p5tzjw","lpiycv","ebdw9u","1ookbab","714dwk","1hu70yk","hobwqm","7dpbpx","7vmqep","c4d79v","1yyhkcy","15lkjjo","1q9mcvr","1izr7si","1yy5aal","vn0yrr","1m3wp4q","12bsqfj","krwajx","8l81zy","6na5q4","2y24fj","li68ai","6nf64v","11xil2b","1epz0fh","1m173d1","124oy3v","1kbu8hg","10335ra","12vsfho","1m1176","95xunl","174qq1k","1obw60b","hgc6lu","15scox9","1k9fay3","shr7pv","1s9d23n","dnl0w7","1gf3j5r","1dgtft4","7ef8f8","yx40kw","7stz2q","1aai96l","1j8jxus","e8rm5m","atv6j6","ts0qly","1luyeat","1mwek35","sg9l1i","o1zbu3","1ac8j74","ftk3jl","ifgy4z","1xy1fx4","14d3mgr","hg8mt2","1jiuhrf","140tz9x","1gz2d9j","syjz65","15o825x","uygc5k","lhap5","k2v7we","i3b7x6","uhcemv","14qyarc"] // ]]> </script><style type="text/css"> .anchor { float: left; padding-right: 4px; margin-left: -20px; } h1 .anchor svg, h2 .anchor svg, h3 .anchor svg, h4 .anchor svg, h5 .anchor svg, h6 .anchor svg { visibility: hidden; } h1:hover .anchor svg, h2:hover .anchor svg, h3:hover .anchor svg, h4:hover .anchor svg, h5:hover .anchor svg, h6:hover .anchor svg, h1 .anchor:focus svg, h2 .anchor:focus svg, h3 .anchor:focus svg, h4 .anchor:focus svg, h5 .anchor:focus svg, h6 .anchor:focus svg { visibility: visible; } </style><script> document.addEventListener("DOMContentLoaded", function(event) { var hash = window.decodeURI(location.hash.replace('#', '')) if (hash !== '') { var element = document.getElementById(hash) if (element) { var offset = element.offsetTop // Wait for the browser to finish rendering before scrolling. setTimeout((function() { window.scrollTo(0, offset - 0) }), 0) } } }) </script><link rel="preconnect" href="https://www.google-analytics.com"/><link rel="dns-prefetch" href="https://www.google-analytics.com"/><link rel="alternate" type="application/rss+xml" href="/feed.xml"/><title data-react-helmet="true">Testing Recipes – React</title><link data-react-helmet="true" rel="canonical" href="https://legacy.reactjs.org/docs/testing-recipes.html"/><link data-react-helmet="true" rel="alternate" href="https://legacy.reactjs.org/docs/testing-recipes.html" hreflang="x-default"/><link data-react-helmet="true" rel="alternate" hreflang="en" href="https://legacy.reactjs.org/docs/testing-recipes.html"/><link data-react-helmet="true" rel="alternate" hreflang="ar" href="https://ar.legacy.reactjs.org/docs/testing-recipes.html"/><link data-react-helmet="true" rel="alternate" hreflang="az" href="https://az.legacy.reactjs.org/docs/testing-recipes.html"/><link data-react-helmet="true" rel="alternate" hreflang="es" href="https://es.legacy.reactjs.org/docs/testing-recipes.html"/><link data-react-helmet="true" rel="alternate" hreflang="fr" href="https://fr.legacy.reactjs.org/docs/testing-recipes.html"/><link data-react-helmet="true" rel="alternate" hreflang="hu" href="https://hu.legacy.reactjs.org/docs/testing-recipes.html"/><link data-react-helmet="true" rel="alternate" hreflang="it" href="https://it.legacy.reactjs.org/docs/testing-recipes.html"/><link data-react-helmet="true" rel="alternate" hreflang="ja" href="https://ja.legacy.reactjs.org/docs/testing-recipes.html"/><link data-react-helmet="true" rel="alternate" hreflang="ko" href="https://ko.legacy.reactjs.org/docs/testing-recipes.html"/><link data-react-helmet="true" rel="alternate" hreflang="mn" href="https://mn.legacy.reactjs.org/docs/testing-recipes.html"/><link data-react-helmet="true" rel="alternate" hreflang="pl" href="https://pl.legacy.reactjs.org/docs/testing-recipes.html"/><link data-react-helmet="true" rel="alternate" hreflang="pt-br" href="https://pt-br.legacy.reactjs.org/docs/testing-recipes.html"/><link data-react-helmet="true" rel="alternate" hreflang="ru" href="https://ru.legacy.reactjs.org/docs/testing-recipes.html"/><link data-react-helmet="true" rel="alternate" hreflang="tr" href="https://tr.legacy.reactjs.org/docs/testing-recipes.html"/><link data-react-helmet="true" rel="alternate" hreflang="uk" href="https://uk.legacy.reactjs.org/docs/testing-recipes.html"/><link data-react-helmet="true" rel="alternate" hreflang="zh-hans" href="https://zh-hans.legacy.reactjs.org/docs/testing-recipes.html"/><link data-react-helmet="true" rel="alternate" hreflang="zh-hant" href="https://zh-hant.legacy.reactjs.org/docs/testing-recipes.html"/><meta data-react-helmet="true" property="og:title" content="Testing Recipes – React"/><meta data-react-helmet="true" property="og:type" content="article"/><meta data-react-helmet="true" property="og:url" content="https://legacy.reactjs.org/docs/testing-recipes.html"/><meta data-react-helmet="true" property="og:image" content="https://legacy.reactjs.org/logo-og.png"/><meta data-react-helmet="true" property="og:description" content="A JavaScript library for building user interfaces"/><meta data-react-helmet="true" property="fb:app_id" content="623268441017527"/><link rel="icon" href="/favicon-32x32.png?v=f4d46f030265b4c48a05c999b8d93791" type="image/png"/><link rel="manifest" href="/manifest.webmanifest" crossorigin="anonymous"/><meta name="theme-color" content="#20232a"/><link rel="apple-touch-icon" sizes="48x48" href="/icons/icon-48x48.png?v=f4d46f030265b4c48a05c999b8d93791"/><link rel="apple-touch-icon" sizes="72x72" href="/icons/icon-72x72.png?v=f4d46f030265b4c48a05c999b8d93791"/><link rel="apple-touch-icon" sizes="96x96" href="/icons/icon-96x96.png?v=f4d46f030265b4c48a05c999b8d93791"/><link rel="apple-touch-icon" sizes="144x144" href="/icons/icon-144x144.png?v=f4d46f030265b4c48a05c999b8d93791"/><link rel="apple-touch-icon" sizes="192x192" href="/icons/icon-192x192.png?v=f4d46f030265b4c48a05c999b8d93791"/><link rel="apple-touch-icon" sizes="256x256" href="/icons/icon-256x256.png?v=f4d46f030265b4c48a05c999b8d93791"/><link rel="apple-touch-icon" sizes="384x384" href="/icons/icon-384x384.png?v=f4d46f030265b4c48a05c999b8d93791"/><link rel="apple-touch-icon" sizes="512x512" href="/icons/icon-512x512.png?v=f4d46f030265b4c48a05c999b8d93791"/><link as="script" rel="preload" href="/webpack-runtime-553c85249a68a5037bdb.js"/><link as="script" rel="preload" href="/framework-5e497f6bfe92c60d1ebf.js"/><link as="script" rel="preload" href="/styles-4c7d46604086483aa196.js"/><link as="script" rel="preload" href="/app-91f91e569a673dd999c0.js"/><link as="script" rel="preload" href="/commons-7c52edc1944d43f8385f.js"/><link as="script" rel="preload" href="/3e8f09252b6028beb8baf8cc63801156f5861675-41a2442ed6f07195fa74.js"/><link as="script" rel="preload" href="/1ed44328c19c4a4d76fd533f20afa4a4705f4d6f-d0e6caf9a2a8d7af058f.js"/><link as="script" rel="preload" href="/component---src-templates-docs-js-f436a098b1c76995b750.js"/><link as="fetch" rel="preload" href="/page-data/docs/testing-recipes.html/page-data.json" crossorigin="anonymous"/><link as="fetch" rel="preload" href="/page-data/app-data.json" crossorigin="anonymous"/></head><body><script> (function() { /* BE CAREFUL! This code is not compiled by our transforms so it needs to stay compatible with older browsers. */ var activeSurveyBanner = null; var socialBanner = null; var snoozeStartDate = null; var today = new Date(); function addTimes(date, days) { var time = new Date(date); time.setDate(time.getDate() + days); return time; } activeSurveyBanner = { storageId: 'reactjs_banner_2021survey', normalHeight: 50, smallHeight: 75, campaignStartDate: '2021-08-16T00:00:00Z', // the Z is for UTC campaignEndDate: '2021-08-31T00:00:00Z', // the Z is for UTC snoozeForDays: 7, }; if (activeSurveyBanner) { try { if (localStorage[activeSurveyBanner.storageId]) { snoozeStartDate = new Date( parseInt(localStorage.getItem(activeSurveyBanner.storageId), 10), ); } } catch (err) { // Ignore. } try { // If it's too early or long past the campaign, don't show the banner: if ( today < new Date(activeSurveyBanner.campaignStartDate) || today > new Date(activeSurveyBanner.campaignEndDate) ) { activeSurveyBanner = null; // If we're in the campaign window, but the snooze has been set and it hasn't expired: } else if ( snoozeStartDate && addTimes(snoozeStartDate, activeSurveyBanner.snoozeForDays) >= today ) { activeSurveyBanner = null; } } catch (err) { // Ignore. } } activeSocialBanner = { normalHeight: 50, smallHeight: 75 }; function updateStyles() { document.documentElement.style.setProperty('--header-height-large', '60px'); document.documentElement.style.setProperty('--header-height-normal', '50px'); document.documentElement.style.setProperty('--header-height-small', '40px'); if (activeSurveyBanner) { document.documentElement.style.setProperty('--survey-banner-display', 'block'); document.documentElement.style.setProperty('--survey-banner-height-normal', activeSurveyBanner.normalHeight + 'px'); document.documentElement.style.setProperty('--survey-banner-height-small', activeSurveyBanner.smallHeight + 'px'); } else { document.documentElement.style.setProperty('--survey-banner-display', 'none'); document.documentElement.style.setProperty('--survey-banner-height-normal', '0px'); document.documentElement.style.setProperty('--survey-banner-height-small', '0px'); } if (activeSocialBanner) { document.documentElement.style.setProperty('--social-banner-display', 'block'); document.documentElement.style.setProperty('--social-banner-height-normal', activeSocialBanner.normalHeight + 'px'); document.documentElement.style.setProperty('--social-banner-height-small', activeSocialBanner.smallHeight + 'px'); } else { document.documentElement.style.setProperty('--social-banner-display', 'none'); document.documentElement.style.setProperty('--social-banner-height-normal', '0px'); document.documentElement.style.setProperty('--social-banner-height-small', '0px'); } } updateStyles(); window.__dismissSurveyBanner = function() { if (activeSurveyBanner) { try { localStorage.setItem(activeSurveyBanner.storageId, Date.now().toString()); } catch (err) { // Ignore. } // Don't show for next navigations within the session. activeSurveyBanner = null; updateStyles(); } }; })(); </script><div id="___gatsby"><div style="outline:none" tabindex="-1" id="gatsby-focus-wrapper"><div class="css-190hivd"><header class="css-19rsoyj"><div class="css-1loxuh3"><div class="css-tctv7l"><div style="position:relative"><div class="css-ebdw9u"><div class="css-lpiycv"><a href="https://surveys.savanta.com/survey/selfserve/21e3/210643?list=2" target="_blank" rel="noopener" class="css-t4a06n"><svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid meet" viewBox="0 0 134 58" class="css-w4tulb"><g><path fill="#ffffff" d="m60.25002,1.61335l32.24974,1.38664l25.24993,5.24999l10.99997,7.99998l3.74999,8.24998l-1.5,8.24998l-6.24998,5.24999l-10.49997,5.24999l-8.99998,2.24999l0.25,2.99999l4.99999,3.74999c0.00018,0.11336 8.50016,3.11335 8.50016,3.11335c0,0 -11.49997,0.5 -11.50015,0.38664c0.00018,0.11336 -13.24979,-1.38664 -13.24996,-1.5c0.00018,0.11336 -4.49981,-2.63663 -4.49999,-2.74999c0.00018,0.11336 -2.74981,-1.63664 -2.74999,-1.75c0.00018,0.11336 -7.9998,1.36336 -7.99998,1.25c0.00018,0.11336 -25.24976,1.61336 -25.24993,1.5c0.00018,0.11336 -21.99976,-1.38664 -21.99994,-1.5c0.00018,0.11336 -17.74978,-3.38663 -17.74995,-3.49999c0.00018,0.11336 -9.7498,-6.38662 -9.74997,-6.49998c0.00018,0.11336 -3.24982,-6.38662 -3.24999,-6.49998c0.00018,0.11336 2.00017,-9.88662 1.99999,-9.99997c0.00018,0.11336 7.75016,-9.38662 7.74998,-9.49997c0.00018,0.11336 19.75012,-9.38662 19.74995,-9.49997c0.00018,0.11336 23.50012,-4.13663 23.49994,-4.24999"></path><rect transform="rotate(-5 37.25019073486327,27.62502670288089)" height="18" width="18" y="18.62503" x="25.7502" fill="#ccc"></rect><rect transform="rotate(-5 66.00012207031251,28.125024795532198)" height="18" width="18" y="19.37502" x="56.00012" fill="#ccc"></rect><rect transform="rotate(-5 91.75005340576159,25.875030517578093)" height="18" width="18" y="19" x="85.00004" fill="#ccc"></rect><g transform="translate(0,58) scale(0.10000000149011612,-0.10000000149011612) "><path fill="#ffffff" d="m570,574c-14,-2 -65,-9 -115,-15c-139,-18 -275,-69 -356,-134c-75,-60 -115,-163 -88,-226c41,-99 236,-151 564,-150c122,1 210,6 246,14c51,13 57,12 67,-4c28,-44 237,-67 326,-35l40,14l-45,6c-86,13 -100,18 -130,44c-29,24 -30,27 -13,34c18,8 18,8 0,5c-53,-6 -4,-72 69,-93c49,-14 49,-14 -51,-9c-117,7 -159,16 -189,45c-18,17 -26,18 -56,9c-18,-5 -114,-13 -211,-16c-165,-5 -197,-3 -363,23c-207,34 -284,116 -224,241c57,119 236,203 479,225c197,18 545,-20 671,-74c110,-47 157,-153 104,-234c-14,-22 -97,-73 -150,-92c-16,-6 -23,-11 -15,-11c25,-2 133,54 162,84c59,59 56,147 -9,211c-33,34 -97,68 -146,79c-124,27 -166,35 -257,44c-124,12 -275,19 -310,15z"></path><path fill="#1a1a1a" d="m377.00009,403.25c-1,-10 -16,-47 -34,-82l-33,-63l-21,36c-24,40 -29,42 -56,21c-21,-16 -18,-22 43,-90l33,-38l19,24c10,13 35,49 56,79c20,30 48,67 62,82c13,15 23,30 20,32c-2,2 -23,7 -46,11c-38,6 -43,4 -43,-12z"></path><path fill="#1a1a1a" d="m674.7493,403c-1,-10 -16,-47 -34,-82l-33,-63l-21,36c-24,40 -29,42 -56,21c-21,-16 -18,-22 43,-90l33,-38l19,24c10,13 35,49 56,79c20,30 48,67 62,82c13,15 23,30 20,32c-2,2 -23,7 -46,11c-38,6 -43,4 -43,-12z"></path><path fill="#1a1a1a" d="m965.49854,402.99999c-1,-10 -16,-47 -34,-82l-33,-63l-21,36c-24,40 -29,42 -56,21c-21,-16 -18,-22 43,-90l33,-38l19,24c10,13 35,49 56,79c20,30 48,67 62,82c13,15 23,30 20,32c-2,2 -23,7 -46,11c-38,6 -43,4 -43,-12z"></path></g></g></svg></a><span class="css-lcvzl3"><span class="css-1e8x600">We want to hear from you!</span><a href="https://surveys.savanta.com/survey/selfserve/21e3/210643?list=2" target="_blank" rel="noopener" class="css-15dgx4v"><span class="css-1og5p3u">Take our 2021 Community Survey!</span><svg x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="css-1ookbab"><path fill="currentColor" d=" M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0, 0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z "></path><polygon fill="currentColor" points=" 45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8, 14.9 62.8,22.9 71.5,22.9 "></polygon></svg></a></span><div class="css-p5tzjw"><button class="css-w59gkz"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 5.8 5.8" alt="close" class="css-s3feo0"><path d="M5.8 5.16L3.54 2.9 5.8.65 5.16 0 2.9 2.26.65 0 0 .65 2.26 2.9 0 5.16l.65.64L2.9 3.54 5.16 5.8l.64-.64z" fill="currentColor"></path></svg></button></div></div></div><div class="css-1hu70yk"><div class="css-lpiycv"><span class="css-714dwk"><span class="css-1e8x600">This site is no longer updated.</span><a href="https://react.dev/blog/2023/03/16/introducing-react-dev" target="_blank" rel="noopener" class="css-1og5p3u"><span class="css-1og5p3u">Go to react.dev</span></a></span></div></div></div></div></div><div class="css-tctv7l"><div class="css-heonw3"><a class="css-4ivotw" href="/"><img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9Ii0xMS41IC0xMC4yMzE3NCAyMyAyMC40NjM0OCI+CiAgPHRpdGxlPlJlYWN0IExvZ288L3RpdGxlPgogIDxjaXJjbGUgY3g9IjAiIGN5PSIwIiByPSIyLjA1IiBmaWxsPSIjNjFkYWZiIi8+CiAgPGcgc3Ryb2tlPSIjNjFkYWZiIiBzdHJva2Utd2lkdGg9IjEiIGZpbGw9Im5vbmUiPgogICAgPGVsbGlwc2Ugcng9IjExIiByeT0iNC4yIi8+CiAgICA8ZWxsaXBzZSByeD0iMTEiIHJ5PSI0LjIiIHRyYW5zZm9ybT0icm90YXRlKDYwKSIvPgogICAgPGVsbGlwc2Ugcng9IjExIiByeT0iNC4yIiB0cmFuc2Zvcm09InJvdGF0ZSgxMjApIi8+CiAgPC9nPgo8L3N2Zz4K" alt="" height="20"/><span class="css-184keb2">React</span></a><nav class="css-79txt3"><a class="css-li68ai" href="/docs/getting-started.html">Docs<span class="css-2y24fj"></span></a><a class="css-hobwqm" href="/tutorial/tutorial.html">Tutorial</a><a class="css-hobwqm" href="/blog/">Blog</a><a class="css-hobwqm" href="/community/support.html">Community</a></nav><form class="css-7vmqep"><input type="search" id="algolia-doc-search" placeholder="Search" aria-label="Search docs" class="css-7dpbpx"/></form><div class="css-nypjs8"><a class="css-zvm479" href="/versions">v<!-- -->18.2.0</a><a class="css-1upvlu3" href="/languages"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M0 0h24v24H0z" fill="none"></path><path d=" M12.87 15.07l-2.54-2.51.03-.03c1.74-1.94 2.98-4.17 3.71-6.53H17V4h-7V2H8v2H1v1.99h11.17C11.5 7.92 10.44 9.75 9 11.35 8.07 10.32 7.3 9.19 6.69 8h-2c.73 1.63 1.73 3.17 2.98 4.56l-5.09 5.02L4 19l5-5 3.11 3.11.76-2.04zM18.5 10h-2L12 22h2l1.12-3h4.75L21 22h2l-4.5-12zm-2.62 7l1.62-4.33L19.12 17h-3.24z " class="css-c4d79v"></path></svg> <span class="css-1rsw1pf">Languages</span></a><a href="https://github.com/facebook/react/" target="_blank" rel="noopener" class="css-6oo1gu">GitHub<svg x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="css-1yyhkcy"><path fill="currentColor" d=" M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0, 0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z "></path><polygon fill="currentColor" points=" 45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8, 14.9 62.8,22.9 71.5,22.9 "></polygon></svg></a></div></div></div></header><div class="css-xbsqlp css-15lkjjo"><div class="css-1m1176 css-95xunl"><div class="css-12vsfho"><div class="css-tctv7l"><div class="css-10335ra"><article class="css-174qq1k"><header class="css-hgc6lu"><h1 class="css-1obw60b">Testing Recipes</h1></header><div class="css-124oy3v"><div class="css-6nf64v"><p>Common testing patterns for React components.</p> <blockquote> <p>Note:</p> <p>This page assumes you’re using <a href="https://jestjs.io/" target="_blank" rel="nofollow noopener noreferrer">Jest</a> as a test runner. If you use a different test runner, you may need to adjust the API, but the overall shape of the solution will likely be the same. Read more details on setting up a testing environment on the <a href="/docs/testing-environments.html">Testing Environments</a> page.</p> </blockquote> <p>On this page, we will primarily use function components. However, these testing strategies don’t depend on implementation details, and work just as well for class components too.</p> <ul> <li><a href="#setup--teardown">Setup/Teardown</a></li> <li><a href="#act"><code class="gatsby-code-text">act()</code></a></li> <li><a href="#rendering">Rendering</a></li> <li><a href="#data-fetching">Data Fetching</a></li> <li><a href="#mocking-modules">Mocking Modules</a></li> <li><a href="#events">Events</a></li> <li><a href="#timers">Timers</a></li> <li><a href="#snapshot-testing">Snapshot Testing</a></li> <li><a href="#multiple-renderers">Multiple Renderers</a></li> <li><a href="#something-missing">Something Missing?</a></li> </ul> <hr> <h3 id="setup--teardown"><a href="#setup--teardown" aria-hidden class="anchor"><svg aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Setup/Teardown </h3> <p>For each test, we usually want to render our React tree to a DOM element that’s attached to <code class="gatsby-code-text">document</code>. This is important so that it can receive DOM events. When the test ends, we want to “clean up” and unmount the tree from the <code class="gatsby-code-text">document</code>.</p> <p>A common way to do it is to use a pair of <code class="gatsby-code-text">beforeEach</code> and <code class="gatsby-code-text">afterEach</code> blocks so that they’ll always run and isolate the effects of a test to itself:</p> <div class="gatsby-highlight" data-language="jsx"><pre class="gatsby-code-jsx"><code class="gatsby-code-jsx"><span class="token keyword">import</span> <span class="token punctuation">{</span> unmountComponentAtNode <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-dom"</span><span class="token punctuation">;</span> <span class="token keyword">let</span> container <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span> <span class="token function">beforeEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token comment">// setup a DOM element as a render target</span> container <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">"div"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> document<span class="token punctuation">.</span>body<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>container<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">afterEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token comment">// cleanup on exiting</span> <span class="token function">unmountComponentAtNode</span><span class="token punctuation">(</span>container<span class="token punctuation">)</span><span class="token punctuation">;</span> container<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> container <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div> <p>You may use a different pattern, but keep in mind that we want to execute the cleanup <em>even if a test fails</em>. Otherwise, tests can become “leaky”, and one test can change the behavior of another test. That makes them difficult to debug.</p> <hr> <h3 id="act"><a href="#act" aria-hidden class="anchor"><svg aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a><code class="gatsby-code-text">act()</code> </h3> <p>When writing UI tests, tasks like rendering, user events, or data fetching can be considered as “units” of interaction with a user interface. <code class="gatsby-code-text">react-dom/test-utils</code> provides a helper called <a href="/docs/test-utils.html#act"><code class="gatsby-code-text">act()</code></a> that makes sure all updates related to these “units” have been processed and applied to the DOM before you make any assertions:</p> <div class="gatsby-highlight" data-language="jsx"><pre class="gatsby-code-jsx"><code class="gatsby-code-jsx"><span class="token function">act</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token comment">// render components</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// make assertions</span></code></pre></div> <p>This helps make your tests run closer to what real users would experience when using your application. The rest of these examples use <code class="gatsby-code-text">act()</code> to make these guarantees.</p> <p>You might find using <code class="gatsby-code-text">act()</code> directly a bit too verbose. To avoid some of the boilerplate, you could use a library like <a href="https://testing-library.com/react" target="_blank" rel="nofollow noopener noreferrer">React Testing Library</a>, whose helpers are wrapped with <code class="gatsby-code-text">act()</code>.</p> <blockquote> <p>Note:</p> <p>The name <code class="gatsby-code-text">act</code> comes from the <a href="http://wiki.c2.com/?ArrangeActAssert" target="_blank" rel="nofollow noopener noreferrer">Arrange-Act-Assert</a> pattern.</p> </blockquote> <hr> <h3 id="rendering"><a href="#rendering" aria-hidden class="anchor"><svg aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Rendering </h3> <p>Commonly, you might want to test whether a component renders correctly for given props. Consider a simple component that renders a message based on a prop:</p> <div class="gatsby-highlight" data-language="jsx"><pre class="gatsby-code-jsx"><code class="gatsby-code-jsx"><span class="token comment">// hello.js</span> <span class="token keyword">import</span> React <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">Hello</span><span class="token punctuation">(</span><span class="token parameter">props</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>props<span class="token punctuation">.</span>name<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>h1</span><span class="token punctuation">></span></span><span class="token plain-text">Hello, </span><span class="token punctuation">{</span>props<span class="token punctuation">.</span>name<span class="token punctuation">}</span><span class="token plain-text">!</span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>h1</span><span class="token punctuation">></span></span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span><span class="token punctuation">></span></span><span class="token plain-text">Hey, stranger</span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span></code></pre></div> <p>We can write a test for this component:</p> <div class="gatsby-highlight has-highlighted-lines" data-language="jsx"><pre class="gatsby-code-jsx"><code class="gatsby-code-jsx"><span class="token comment">// hello.test.js</span> <span class="token keyword">import</span> React <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> render<span class="token punctuation">,</span> unmountComponentAtNode <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-dom"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> act <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-dom/test-utils"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> Hello <span class="token keyword">from</span> <span class="token string">"./hello"</span><span class="token punctuation">;</span> <span class="token keyword">let</span> container <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span> <span class="token function">beforeEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token comment">// setup a DOM element as a render target</span> container <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">"div"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> document<span class="token punctuation">.</span>body<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>container<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">afterEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token comment">// cleanup on exiting</span> <span class="token function">unmountComponentAtNode</span><span class="token punctuation">(</span>container<span class="token punctuation">)</span><span class="token punctuation">;</span> container<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> container <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">it</span><span class="token punctuation">(</span><span class="token string">"renders with or without a name"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="gatsby-highlight-code-line"> <span class="token function">act</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span></span><span class="gatsby-highlight-code-line"> <span class="token function">render</span><span class="token punctuation">(</span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">Hello</span></span> <span class="token punctuation">/></span></span><span class="token punctuation">,</span> container<span class="token punctuation">)</span><span class="token punctuation">;</span></span><span class="gatsby-highlight-code-line"> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span><span class="gatsby-highlight-code-line"> <span class="token function">expect</span><span class="token punctuation">(</span>container<span class="token punctuation">.</span>textContent<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toBe</span><span class="token punctuation">(</span><span class="token string">"Hey, stranger"</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span> <span class="token function">act</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">render</span><span class="token punctuation">(</span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">Hello</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Jenny<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span><span class="token punctuation">,</span> container<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">expect</span><span class="token punctuation">(</span>container<span class="token punctuation">.</span>textContent<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toBe</span><span class="token punctuation">(</span><span class="token string">"Hello, Jenny!"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">act</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">render</span><span class="token punctuation">(</span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">Hello</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Margaret<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span><span class="token punctuation">,</span> container<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">expect</span><span class="token punctuation">(</span>container<span class="token punctuation">.</span>textContent<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toBe</span><span class="token punctuation">(</span><span class="token string">"Hello, Margaret!"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div> <hr> <h3 id="data-fetching"><a href="#data-fetching" aria-hidden class="anchor"><svg aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Data Fetching </h3> <p>Instead of calling real APIs in all your tests, you can mock requests with dummy data. Mocking data fetching with “fake” data prevents flaky tests due to an unavailable backend, and makes them run faster. Note: you may still want to run a subset of tests using an <a href="/docs/testing-environments.html#end-to-end-tests-aka-e2e-tests">“end-to-end”</a> framework that tells whether the whole app is working together.</p> <div class="gatsby-highlight" data-language="jsx"><pre class="gatsby-code-jsx"><code class="gatsby-code-jsx"><span class="token comment">// user.js</span> <span class="token keyword">import</span> React<span class="token punctuation">,</span> <span class="token punctuation">{</span> useState<span class="token punctuation">,</span> useEffect <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">User</span><span class="token punctuation">(</span><span class="token parameter">props</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>user<span class="token punctuation">,</span> setUser<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">fetchUserData</span><span class="token punctuation">(</span><span class="token parameter">id</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> response <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token string">"/"</span> <span class="token operator">+</span> id<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">setUser</span><span class="token punctuation">(</span><span class="token keyword">await</span> response<span class="token punctuation">.</span><span class="token function">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">fetchUserData</span><span class="token punctuation">(</span>props<span class="token punctuation">.</span>id<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>props<span class="token punctuation">.</span>id<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>user<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token string">"loading..."</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>details</span><span class="token punctuation">></span></span><span class="token plain-text"> </span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>summary</span><span class="token punctuation">></span></span><span class="token punctuation">{</span>user<span class="token punctuation">.</span>name<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>summary</span><span class="token punctuation">></span></span><span class="token plain-text"> </span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>strong</span><span class="token punctuation">></span></span><span class="token punctuation">{</span>user<span class="token punctuation">.</span>age<span class="token punctuation">}</span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>strong</span><span class="token punctuation">></span></span><span class="token plain-text"> years old </span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>br</span> <span class="token punctuation">/></span></span><span class="token plain-text"> lives in </span><span class="token punctuation">{</span>user<span class="token punctuation">.</span>address<span class="token punctuation">}</span><span class="token plain-text"> </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>details</span><span class="token punctuation">></span></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div> <p>We can write tests for it:</p> <div class="gatsby-highlight has-highlighted-lines" data-language="jsx"><pre class="gatsby-code-jsx"><code class="gatsby-code-jsx"><span class="token comment">// user.test.js</span> <span class="token keyword">import</span> React <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> render<span class="token punctuation">,</span> unmountComponentAtNode <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-dom"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> act <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-dom/test-utils"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> User <span class="token keyword">from</span> <span class="token string">"./user"</span><span class="token punctuation">;</span> <span class="token keyword">let</span> container <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span> <span class="token function">beforeEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token comment">// setup a DOM element as a render target</span> container <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">"div"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> document<span class="token punctuation">.</span>body<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>container<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">afterEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token comment">// cleanup on exiting</span> <span class="token function">unmountComponentAtNode</span><span class="token punctuation">(</span>container<span class="token punctuation">)</span><span class="token punctuation">;</span> container<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> container <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">it</span><span class="token punctuation">(</span><span class="token string">"renders user data"</span><span class="token punctuation">,</span> <span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="gatsby-highlight-code-line"> <span class="token keyword">const</span> fakeUser <span class="token operator">=</span> <span class="token punctuation">{</span></span><span class="gatsby-highlight-code-line"> <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">"Joni Baez"</span><span class="token punctuation">,</span></span><span class="gatsby-highlight-code-line"> <span class="token literal-property property">age</span><span class="token operator">:</span> <span class="token string">"32"</span><span class="token punctuation">,</span></span><span class="gatsby-highlight-code-line"> <span class="token literal-property property">address</span><span class="token operator">:</span> <span class="token string">"123, Charming Avenue"</span></span><span class="gatsby-highlight-code-line"> <span class="token punctuation">}</span><span class="token punctuation">;</span></span><span class="gatsby-highlight-code-line"></span><span class="gatsby-highlight-code-line"> jest<span class="token punctuation">.</span><span class="token function">spyOn</span><span class="token punctuation">(</span>global<span class="token punctuation">,</span> <span class="token string">"fetch"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">mockImplementation</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span></span><span class="gatsby-highlight-code-line"> Promise<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span><span class="token punctuation">{</span></span><span class="gatsby-highlight-code-line"> <span class="token function-variable function">json</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> Promise<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span>fakeUser<span class="token punctuation">)</span></span><span class="gatsby-highlight-code-line"> <span class="token punctuation">}</span><span class="token punctuation">)</span></span><span class="gatsby-highlight-code-line"> <span class="token punctuation">)</span><span class="token punctuation">;</span></span> <span class="token comment">// Use the asynchronous version of act to apply resolved promises</span> <span class="token keyword">await</span> <span class="token function">act</span><span class="token punctuation">(</span><span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">render</span><span class="token punctuation">(</span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">User</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>123<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span><span class="token punctuation">,</span> container<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">expect</span><span class="token punctuation">(</span>container<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">"summary"</span><span class="token punctuation">)</span><span class="token punctuation">.</span>textContent<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toBe</span><span class="token punctuation">(</span>fakeUser<span class="token punctuation">.</span>name<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">expect</span><span class="token punctuation">(</span>container<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">"strong"</span><span class="token punctuation">)</span><span class="token punctuation">.</span>textContent<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toBe</span><span class="token punctuation">(</span>fakeUser<span class="token punctuation">.</span>age<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">expect</span><span class="token punctuation">(</span>container<span class="token punctuation">.</span>textContent<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toContain</span><span class="token punctuation">(</span>fakeUser<span class="token punctuation">.</span>address<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="gatsby-highlight-code-line"> <span class="token comment">// remove the mock to ensure tests are completely isolated</span></span><span class="gatsby-highlight-code-line"> global<span class="token punctuation">.</span>fetch<span class="token punctuation">.</span><span class="token function">mockRestore</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div> <hr> <h3 id="mocking-modules"><a href="#mocking-modules" aria-hidden class="anchor"><svg aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Mocking Modules </h3> <p>Some modules might not work well inside a testing environment, or may not be as essential to the test itself. Mocking out these modules with dummy replacements can make it easier to write tests for your own code.</p> <p>Consider a <code class="gatsby-code-text">Contact</code> component that embeds a third-party <code class="gatsby-code-text">GoogleMap</code> component:</p> <div class="gatsby-highlight" data-language="jsx"><pre class="gatsby-code-jsx"><code class="gatsby-code-jsx"><span class="token comment">// map.js</span> <span class="token keyword">import</span> React <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> LoadScript<span class="token punctuation">,</span> GoogleMap <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-google-maps"</span><span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">Map</span><span class="token punctuation">(</span><span class="token parameter">props</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">LoadScript</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>script-loader<span class="token punctuation">"</span></span> <span class="token attr-name">googleMapsApiKey</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>YOUR_API_KEY<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token plain-text"> </span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">GoogleMap</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>example-map<span class="token punctuation">"</span></span> <span class="token attr-name">center</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>props<span class="token punctuation">.</span>center<span class="token punctuation">}</span></span> <span class="token punctuation">/></span></span><span class="token plain-text"> </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span><span class="token class-name">LoadScript</span></span><span class="token punctuation">></span></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">// contact.js</span> <span class="token keyword">import</span> React <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> Map <span class="token keyword">from</span> <span class="token string">"./map"</span><span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">Contact</span><span class="token punctuation">(</span><span class="token parameter">props</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span><span class="token punctuation">></span></span><span class="token plain-text"> </span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>address</span><span class="token punctuation">></span></span><span class="token plain-text"> Contact </span><span class="token punctuation">{</span>props<span class="token punctuation">.</span>name<span class="token punctuation">}</span><span class="token plain-text"> via</span><span class="token punctuation">{</span><span class="token string">" "</span><span class="token punctuation">}</span><span class="token plain-text"> </span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>a</span> <span class="token attr-name">data-testid</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>email<span class="token punctuation">"</span></span> <span class="token attr-name">href</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token string">"mailto:"</span> <span class="token operator">+</span> props<span class="token punctuation">.</span>email<span class="token punctuation">}</span></span><span class="token punctuation">></span></span><span class="token plain-text"> email </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>a</span><span class="token punctuation">></span></span><span class="token plain-text"> or on their </span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>a</span> <span class="token attr-name">data-testid</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>site<span class="token punctuation">"</span></span> <span class="token attr-name">href</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>props<span class="token punctuation">.</span>site<span class="token punctuation">}</span></span><span class="token punctuation">></span></span><span class="token plain-text"> website </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>a</span><span class="token punctuation">></span></span><span class="token plain-text">. </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>address</span><span class="token punctuation">></span></span><span class="token plain-text"> </span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">Map</span></span> <span class="token attr-name">center</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>props<span class="token punctuation">.</span>center<span class="token punctuation">}</span></span> <span class="token punctuation">/></span></span><span class="token plain-text"> </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div> <p>If we don’t want to load this component in our tests, we can mock out the dependency itself to a dummy component, and run our tests:</p> <div class="gatsby-highlight has-highlighted-lines" data-language="jsx"><pre class="gatsby-code-jsx"><code class="gatsby-code-jsx"><span class="token comment">// contact.test.js</span> <span class="token keyword">import</span> React <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> render<span class="token punctuation">,</span> unmountComponentAtNode <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-dom"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> act <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-dom/test-utils"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> Contact <span class="token keyword">from</span> <span class="token string">"./contact"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> MockedMap <span class="token keyword">from</span> <span class="token string">"./map"</span><span class="token punctuation">;</span> <span class="gatsby-highlight-code-line">jest<span class="token punctuation">.</span><span class="token function">mock</span><span class="token punctuation">(</span><span class="token string">"./map"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span></span><span class="gatsby-highlight-code-line"> <span class="token keyword">return</span> <span class="token keyword">function</span> <span class="token function">DummyMap</span><span class="token punctuation">(</span><span class="token parameter">props</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span><span class="gatsby-highlight-code-line"> <span class="token keyword">return</span> <span class="token punctuation">(</span></span><span class="gatsby-highlight-code-line"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">data-testid</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>map<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token plain-text"></span></span><span class="gatsby-highlight-code-line"><span class="token plain-text"> </span><span class="token punctuation">{</span>props<span class="token punctuation">.</span>center<span class="token punctuation">.</span>lat<span class="token punctuation">}</span><span class="token plain-text">:</span><span class="token punctuation">{</span>props<span class="token punctuation">.</span>center<span class="token punctuation">.</span>long<span class="token punctuation">}</span><span class="token plain-text"></span></span><span class="gatsby-highlight-code-line"><span class="token plain-text"> </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span></span><span class="gatsby-highlight-code-line"> <span class="token punctuation">)</span><span class="token punctuation">;</span></span><span class="gatsby-highlight-code-line"> <span class="token punctuation">}</span><span class="token punctuation">;</span></span><span class="gatsby-highlight-code-line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span> <span class="token keyword">let</span> container <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span> <span class="token function">beforeEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token comment">// setup a DOM element as a render target</span> container <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">"div"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> document<span class="token punctuation">.</span>body<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>container<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">afterEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token comment">// cleanup on exiting</span> <span class="token function">unmountComponentAtNode</span><span class="token punctuation">(</span>container<span class="token punctuation">)</span><span class="token punctuation">;</span> container<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> container <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">it</span><span class="token punctuation">(</span><span class="token string">"should render contact information"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> center <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">lat</span><span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token literal-property property">long</span><span class="token operator">:</span> <span class="token number">0</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token function">act</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">render</span><span class="token punctuation">(</span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">Contact</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Joni Baez<span class="token punctuation">"</span></span> <span class="token attr-name">email</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>test@example.com<span class="token punctuation">"</span></span> <span class="token attr-name">site</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>http://test.com<span class="token punctuation">"</span></span> <span class="token attr-name">center</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>center<span class="token punctuation">}</span></span> <span class="token punctuation">/></span></span><span class="token punctuation">,</span> container <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">expect</span><span class="token punctuation">(</span> container<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">"[data-testid='email']"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getAttribute</span><span class="token punctuation">(</span><span class="token string">"href"</span><span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toEqual</span><span class="token punctuation">(</span><span class="token string">"mailto:test@example.com"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">expect</span><span class="token punctuation">(</span> container<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'[data-testid="site"]'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getAttribute</span><span class="token punctuation">(</span><span class="token string">"href"</span><span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toEqual</span><span class="token punctuation">(</span><span class="token string">"http://test.com"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">expect</span><span class="token punctuation">(</span>container<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'[data-testid="map"]'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>textContent<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toEqual</span><span class="token punctuation">(</span> <span class="token string">"0:0"</span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div> <hr> <h3 id="events"><a href="#events" aria-hidden class="anchor"><svg aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Events </h3> <p>We recommend dispatching real DOM events on DOM elements, and then asserting on the result. Consider a <code class="gatsby-code-text">Toggle</code> component:</p> <div class="gatsby-highlight" data-language="jsx"><pre class="gatsby-code-jsx"><code class="gatsby-code-jsx"><span class="token comment">// toggle.js</span> <span class="token keyword">import</span> React<span class="token punctuation">,</span> <span class="token punctuation">{</span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">Toggle</span><span class="token punctuation">(</span><span class="token parameter">props</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>state<span class="token punctuation">,</span> setState<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>button</span> <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">setState</span><span class="token punctuation">(</span><span class="token parameter">previousState</span> <span class="token operator">=></span> <span class="token operator">!</span>previousState<span class="token punctuation">)</span><span class="token punctuation">;</span> props<span class="token punctuation">.</span><span class="token function">onChange</span><span class="token punctuation">(</span><span class="token operator">!</span>state<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">}</span></span> <span class="token attr-name">data-testid</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>toggle<span class="token punctuation">"</span></span> <span class="token punctuation">></span></span><span class="token plain-text"> </span><span class="token punctuation">{</span>state <span class="token operator">===</span> <span class="token boolean">true</span> <span class="token operator">?</span> <span class="token string">"Turn off"</span> <span class="token operator">:</span> <span class="token string">"Turn on"</span><span class="token punctuation">}</span><span class="token plain-text"> </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>button</span><span class="token punctuation">></span></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div> <p>We could write tests for it:</p> <div class="gatsby-highlight has-highlighted-lines" data-language="jsx"><pre class="gatsby-code-jsx"><code class="gatsby-code-jsx"><span class="token comment">// toggle.test.js</span> <span class="token keyword">import</span> React <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> render<span class="token punctuation">,</span> unmountComponentAtNode <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-dom"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> act <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-dom/test-utils"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> Toggle <span class="token keyword">from</span> <span class="token string">"./toggle"</span><span class="token punctuation">;</span> <span class="token keyword">let</span> container <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span> <span class="token function">beforeEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token comment">// setup a DOM element as a render target</span> container <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">"div"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="gatsby-highlight-code-line"> document<span class="token punctuation">.</span>body<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>container<span class="token punctuation">)</span><span class="token punctuation">;</span></span><span class="gatsby-highlight-code-line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span> <span class="token function">afterEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token comment">// cleanup on exiting</span> <span class="token function">unmountComponentAtNode</span><span class="token punctuation">(</span>container<span class="token punctuation">)</span><span class="token punctuation">;</span> container<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> container <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">it</span><span class="token punctuation">(</span><span class="token string">"changes value when clicked"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> onChange <span class="token operator">=</span> jest<span class="token punctuation">.</span><span class="token function">fn</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">act</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">render</span><span class="token punctuation">(</span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">Toggle</span></span> <span class="token attr-name">onChange</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>onChange<span class="token punctuation">}</span></span> <span class="token punctuation">/></span></span><span class="token punctuation">,</span> container<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// get a hold of the button element, and trigger some clicks on it</span> <span class="token keyword">const</span> button <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">"[data-testid=toggle]"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">expect</span><span class="token punctuation">(</span>button<span class="token punctuation">.</span>innerHTML<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toBe</span><span class="token punctuation">(</span><span class="token string">"Turn on"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">act</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> button<span class="token punctuation">.</span><span class="token function">dispatchEvent</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">MouseEvent</span><span class="token punctuation">(</span><span class="token string">"click"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">bubbles</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="gatsby-highlight-code-line"> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span> <span class="token function">expect</span><span class="token punctuation">(</span>onChange<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toHaveBeenCalledTimes</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">expect</span><span class="token punctuation">(</span>button<span class="token punctuation">.</span>innerHTML<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toBe</span><span class="token punctuation">(</span><span class="token string">"Turn off"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">act</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> <span class="token number">5</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> button<span class="token punctuation">.</span><span class="token function">dispatchEvent</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">MouseEvent</span><span class="token punctuation">(</span><span class="token string">"click"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">bubbles</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="gatsby-highlight-code-line"> <span class="token punctuation">}</span></span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">expect</span><span class="token punctuation">(</span>onChange<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toHaveBeenCalledTimes</span><span class="token punctuation">(</span><span class="token number">6</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">expect</span><span class="token punctuation">(</span>button<span class="token punctuation">.</span>innerHTML<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toBe</span><span class="token punctuation">(</span><span class="token string">"Turn on"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div> <p>Different DOM events and their properties are described in <a href="https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent" target="_blank" rel="nofollow noopener noreferrer">MDN</a>. Note that you need to pass <code class="gatsby-code-text">{ bubbles: true }</code> in each event you create for it to reach the React listener because React automatically delegates events to the root.</p> <blockquote> <p>Note:</p> <p>React Testing Library offers a <a href="https://testing-library.com/docs/dom-testing-library/api-events" target="_blank" rel="nofollow noopener noreferrer">more concise helper</a> for firing events.</p> </blockquote> <hr> <h3 id="timers"><a href="#timers" aria-hidden class="anchor"><svg aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Timers </h3> <p>Your code might use timer-based functions like <code class="gatsby-code-text">setTimeout</code> to schedule more work in the future. In this example, a multiple choice panel waits for a selection and advances, timing out if a selection isn’t made in 5 seconds:</p> <div class="gatsby-highlight" data-language="jsx"><pre class="gatsby-code-jsx"><code class="gatsby-code-jsx"><span class="token comment">// card.js</span> <span class="token keyword">import</span> React<span class="token punctuation">,</span> <span class="token punctuation">{</span> useEffect <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">Card</span><span class="token punctuation">(</span><span class="token parameter">props</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> timeoutID <span class="token operator">=</span> <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> props<span class="token punctuation">.</span><span class="token function">onSelect</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">5000</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">clearTimeout</span><span class="token punctuation">(</span>timeoutID<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>props<span class="token punctuation">.</span>onSelect<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token parameter">choice</span> <span class="token operator">=></span> <span class="token punctuation">(</span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>button</span> <span class="token attr-name">key</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>choice<span class="token punctuation">}</span></span> <span class="token attr-name">data-testid</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>choice<span class="token punctuation">}</span></span> <span class="token attr-name">onClick</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> props<span class="token punctuation">.</span><span class="token function">onSelect</span><span class="token punctuation">(</span>choice<span class="token punctuation">)</span><span class="token punctuation">}</span></span> <span class="token punctuation">></span></span><span class="token plain-text"> </span><span class="token punctuation">{</span>choice<span class="token punctuation">}</span><span class="token plain-text"> </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>button</span><span class="token punctuation">></span></span> <span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span></code></pre></div> <p>We can write tests for this component by leveraging <a href="https://jestjs.io/docs/en/timer-mocks" target="_blank" rel="nofollow noopener noreferrer">Jest’s timer mocks</a>, and testing the different states it can be in.</p> <div class="gatsby-highlight has-highlighted-lines" data-language="jsx"><pre class="gatsby-code-jsx"><code class="gatsby-code-jsx"><span class="token comment">// card.test.js</span> <span class="token keyword">import</span> React <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> render<span class="token punctuation">,</span> unmountComponentAtNode <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-dom"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> act <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-dom/test-utils"</span><span class="token punctuation">;</span> <span class="gatsby-highlight-code-line"><span class="token keyword">import</span> Card <span class="token keyword">from</span> <span class="token string">"./card"</span><span class="token punctuation">;</span></span> <span class="token keyword">let</span> container <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span> <span class="token function">beforeEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token comment">// setup a DOM element as a render target</span> container <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">"div"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> document<span class="token punctuation">.</span>body<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>container<span class="token punctuation">)</span><span class="token punctuation">;</span> jest<span class="token punctuation">.</span><span class="token function">useFakeTimers</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">afterEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token comment">// cleanup on exiting</span> <span class="token function">unmountComponentAtNode</span><span class="token punctuation">(</span>container<span class="token punctuation">)</span><span class="token punctuation">;</span> container<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> container <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span> jest<span class="token punctuation">.</span><span class="token function">useRealTimers</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">it</span><span class="token punctuation">(</span><span class="token string">"should select null after timing out"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> onSelect <span class="token operator">=</span> jest<span class="token punctuation">.</span><span class="token function">fn</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">act</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">render</span><span class="token punctuation">(</span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">Card</span></span> <span class="token attr-name">onSelect</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>onSelect<span class="token punctuation">}</span></span> <span class="token punctuation">/></span></span><span class="token punctuation">,</span> container<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="gatsby-highlight-code-line"> <span class="token comment">// move ahead in time by 100ms</span></span> <span class="token function">act</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> jest<span class="token punctuation">.</span><span class="token function">advanceTimersByTime</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">expect</span><span class="token punctuation">(</span>onSelect<span class="token punctuation">)</span><span class="token punctuation">.</span>not<span class="token punctuation">.</span><span class="token function">toHaveBeenCalled</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="gatsby-highlight-code-line"> <span class="token comment">// and then move ahead by 5 seconds</span></span> <span class="token function">act</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> jest<span class="token punctuation">.</span><span class="token function">advanceTimersByTime</span><span class="token punctuation">(</span><span class="token number">5000</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">expect</span><span class="token punctuation">(</span>onSelect<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toHaveBeenCalledWith</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">it</span><span class="token punctuation">(</span><span class="token string">"should cleanup on being removed"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> onSelect <span class="token operator">=</span> jest<span class="token punctuation">.</span><span class="token function">fn</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">act</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">render</span><span class="token punctuation">(</span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">Card</span></span> <span class="token attr-name">onSelect</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>onSelect<span class="token punctuation">}</span></span> <span class="token punctuation">/></span></span><span class="token punctuation">,</span> container<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="gatsby-highlight-code-line"></span> <span class="token function">act</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> jest<span class="token punctuation">.</span><span class="token function">advanceTimersByTime</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">expect</span><span class="token punctuation">(</span>onSelect<span class="token punctuation">)</span><span class="token punctuation">.</span>not<span class="token punctuation">.</span><span class="token function">toHaveBeenCalled</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// unmount the app</span> <span class="token function">act</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">render</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">,</span> container<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="gatsby-highlight-code-line"></span> <span class="token function">act</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> jest<span class="token punctuation">.</span><span class="token function">advanceTimersByTime</span><span class="token punctuation">(</span><span class="token number">5000</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">expect</span><span class="token punctuation">(</span>onSelect<span class="token punctuation">)</span><span class="token punctuation">.</span>not<span class="token punctuation">.</span><span class="token function">toHaveBeenCalled</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">it</span><span class="token punctuation">(</span><span class="token string">"should accept selections"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> onSelect <span class="token operator">=</span> jest<span class="token punctuation">.</span><span class="token function">fn</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">act</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">render</span><span class="token punctuation">(</span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">Card</span></span> <span class="token attr-name">onSelect</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>onSelect<span class="token punctuation">}</span></span> <span class="token punctuation">/></span></span><span class="token punctuation">,</span> container<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">act</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> container <span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">"[data-testid='2']"</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">dispatchEvent</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">MouseEvent</span><span class="token punctuation">(</span><span class="token string">"click"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">bubbles</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">expect</span><span class="token punctuation">(</span>onSelect<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toHaveBeenCalledWith</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div> <p>You can use fake timers only in some tests. Above, we enabled them by calling <code class="gatsby-code-text">jest.useFakeTimers()</code>. The main advantage they provide is that your test doesn’t actually have to wait five seconds to execute, and you also didn’t need to make the component code more convoluted just for testing.</p> <hr> <h3 id="snapshot-testing"><a href="#snapshot-testing" aria-hidden class="anchor"><svg aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Snapshot Testing </h3> <p>Frameworks like Jest also let you save “snapshots” of data with <a href="https://jestjs.io/docs/en/snapshot-testing" target="_blank" rel="nofollow noopener noreferrer"><code class="gatsby-code-text">toMatchSnapshot</code> / <code class="gatsby-code-text">toMatchInlineSnapshot</code></a>. With these, we can “save” the rendered component output and ensure that a change to it has to be explicitly committed as a change to the snapshot.</p> <p>In this example, we render a component and format the rendered HTML with the <a href="https://www.npmjs.com/package/pretty" target="_blank" rel="nofollow noopener noreferrer"><code class="gatsby-code-text">pretty</code></a> package, before saving it as an inline snapshot:</p> <div class="gatsby-highlight has-highlighted-lines" data-language="jsx"><pre class="gatsby-code-jsx"><code class="gatsby-code-jsx"><span class="token comment">// hello.test.js, again</span> <span class="token keyword">import</span> React <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> render<span class="token punctuation">,</span> unmountComponentAtNode <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-dom"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> act <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-dom/test-utils"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> pretty <span class="token keyword">from</span> <span class="token string">"pretty"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> Hello <span class="token keyword">from</span> <span class="token string">"./hello"</span><span class="token punctuation">;</span> <span class="token keyword">let</span> container <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span> <span class="token function">beforeEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token comment">// setup a DOM element as a render target</span> container <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">"div"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> document<span class="token punctuation">.</span>body<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>container<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">afterEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token comment">// cleanup on exiting</span> <span class="token function">unmountComponentAtNode</span><span class="token punctuation">(</span>container<span class="token punctuation">)</span><span class="token punctuation">;</span> container<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> container <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">it</span><span class="token punctuation">(</span><span class="token string">"should render a greeting"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">act</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">render</span><span class="token punctuation">(</span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">Hello</span></span> <span class="token punctuation">/></span></span><span class="token punctuation">,</span> container<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="gatsby-highlight-code-line"> <span class="token function">expect</span><span class="token punctuation">(</span></span><span class="gatsby-highlight-code-line"> <span class="token function">pretty</span><span class="token punctuation">(</span>container<span class="token punctuation">.</span>innerHTML<span class="token punctuation">)</span></span><span class="gatsby-highlight-code-line"> <span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toMatchInlineSnapshot</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* ... gets filled automatically by jest ... */</span></span> <span class="token function">act</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">render</span><span class="token punctuation">(</span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">Hello</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Jenny<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span><span class="token punctuation">,</span> container<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">expect</span><span class="token punctuation">(</span> <span class="token function">pretty</span><span class="token punctuation">(</span>container<span class="token punctuation">.</span>innerHTML<span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toMatchInlineSnapshot</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* ... gets filled automatically by jest ... */</span> <span class="token function">act</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">render</span><span class="token punctuation">(</span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">Hello</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Margaret<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span><span class="token punctuation">,</span> container<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">expect</span><span class="token punctuation">(</span> <span class="token function">pretty</span><span class="token punctuation">(</span>container<span class="token punctuation">.</span>innerHTML<span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toMatchInlineSnapshot</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* ... gets filled automatically by jest ... */</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div> <p>It’s typically better to make more specific assertions than to use snapshots. These kinds of tests include implementation details so they break easily, and teams can get desensitized to snapshot breakages. Selectively <a href="#mocking-modules">mocking some child components</a> can help reduce the size of snapshots and keep them readable for the code review.</p> <hr> <h3 id="multiple-renderers"><a href="#multiple-renderers" aria-hidden class="anchor"><svg aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Multiple Renderers </h3> <p>In rare cases, you may be running a test on a component that uses multiple renderers. For example, you may be running snapshot tests on a component with <code class="gatsby-code-text">react-test-renderer</code>, that internally uses <code class="gatsby-code-text">render</code> from <code class="gatsby-code-text">react-dom</code> inside a child component to render some content. In this scenario, you can wrap updates with <code class="gatsby-code-text">act()</code>s corresponding to their renderers.</p> <div class="gatsby-highlight" data-language="jsx"><pre class="gatsby-code-jsx"><code class="gatsby-code-jsx"><span class="token keyword">import</span> <span class="token punctuation">{</span> act <span class="token keyword">as</span> domAct <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-dom/test-utils"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> act <span class="token keyword">as</span> testAct<span class="token punctuation">,</span> create <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-test-renderer"</span><span class="token punctuation">;</span> <span class="token comment">// ...</span> <span class="token keyword">let</span> root<span class="token punctuation">;</span> <span class="token function">domAct</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">testAct</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> root <span class="token operator">=</span> <span class="token function">create</span><span class="token punctuation">(</span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token class-name">App</span></span> <span class="token punctuation">/></span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">expect</span><span class="token punctuation">(</span>root<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toMatchSnapshot</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre></div> <hr> <h3 id="something-missing"><a href="#something-missing" aria-hidden class="anchor"><svg aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Something Missing? </h3> <p>If some common scenario is not covered, please let us know on the <a href="https://github.com/reactjs/reactjs.org/issues" target="_blank" rel="nofollow noopener noreferrer">issue tracker</a> for the documentation website.</p></div><div class="css-1m173d1"><span class="css-11xil2b"><span>Is this page useful?<button aria-label="Yes" class="css-1k9fay3"><svg focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 81.13 89.76" class="css-15scox9"><path d="M22.9 6a18.57 18.57 0 002.67 8.4 25.72 25.72 0 008.65 7.66c3.86 2 8.67 7.13 13.51 11 3.86 3.11 8.57 7.11 11.54 8.45s13.59.26 14.64 1.17c1.88 1.63 1.55 9-.11 15.25-1.61 5.86-5.96 10.55-6.48 16.86-.4 4.83-2.7 4.88-10.93 4.88h-1.35c-3.82 0-8.24 2.93-12.92 3.62a68 68 0 01-9.73.5c-3.57 0-7.86-.08-13.25-.08-3.56 0-4.71-1.83-4.71-4.48h8.42a3.51 3.51 0 000-7H12.28a2.89 2.89 0 01-2.88-2.88 1.91 1.91 0 01.77-1.78h16.46a3.51 3.51 0 000-7H12.29c-3.21 0-4.84-1.83-4.84-4a6.41 6.41 0 011.17-3.78h19.06a3.5 3.5 0 100-7H9.75A3.51 3.51 0 016 42.27a3.45 3.45 0 013.75-3.48h13.11c5.61 0 7.71-3 5.71-5.52-4.43-4.74-10.84-12.62-11-18.71-.15-6.51 2.6-7.83 5.36-8.56m0-6a6.18 6.18 0 00-1.53.2c-6.69 1.77-10 6.65-9.82 14.5.08 5.09 2.99 11.18 8.52 18.09H9.74a9.52 9.52 0 00-6.23 16.9 12.52 12.52 0 00-2.07 6.84 9.64 9.64 0 003.65 7.7 7.85 7.85 0 00-1.7 5.13 8.9 8.9 0 005.3 8.13 6 6 0 00-.26 1.76c0 6.37 4.2 10.48 10.71 10.48h13.25a73.75 73.75 0 0010.6-.56 35.89 35.89 0 007.58-2.18 17.83 17.83 0 014.48-1.34h1.35c4.69 0 7.79 0 10.5-1 3.85-1.44 6-4.59 6.41-9.38.2-2.46 1.42-4.85 2.84-7.62a41.3 41.3 0 003.42-8.13 48 48 0 001.59-10.79c.1-5.13-1-8.48-3.35-10.55-2.16-1.87-4.64-1.87-9.6-1.88a46.86 46.86 0 01-6.64-.29c-1.92-.94-5.72-4-8.51-6.3l-1.58-1.28c-1.6-1.3-3.27-2.79-4.87-4.23-3.33-3-6.47-5.79-9.61-7.45a20.2 20.2 0 01-6.43-5.53 12.44 12.44 0 01-1.72-5.36 6 6 0 00-6-5.86z"></path></svg></button><button aria-label="No" class="css-1s9d23n"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 81.13 89.76" class="css-shr7pv"><path d="M22.9 6a18.57 18.57 0 002.67 8.4 25.72 25.72 0 008.65 7.66c3.86 2 8.67 7.13 13.51 11 3.86 3.11 8.57 7.11 11.54 8.45s13.59.26 14.64 1.17c1.88 1.63 1.55 9-.11 15.25-1.61 5.86-5.96 10.55-6.48 16.86-.4 4.83-2.7 4.88-10.93 4.88h-1.35c-3.82 0-8.24 2.93-12.92 3.62a68 68 0 01-9.73.5c-3.57 0-7.86-.08-13.25-.08-3.56 0-4.71-1.83-4.71-4.48h8.42a3.51 3.51 0 000-7H12.28a2.89 2.89 0 01-2.88-2.88 1.91 1.91 0 01.77-1.78h16.46a3.51 3.51 0 000-7H12.29c-3.21 0-4.84-1.83-4.84-4a6.41 6.41 0 011.17-3.78h19.06a3.5 3.5 0 100-7H9.75A3.51 3.51 0 016 42.27a3.45 3.45 0 013.75-3.48h13.11c5.61 0 7.71-3 5.71-5.52-4.43-4.74-10.84-12.62-11-18.71-.15-6.51 2.6-7.83 5.36-8.56m0-6a6.18 6.18 0 00-1.53.2c-6.69 1.77-10 6.65-9.82 14.5.08 5.09 2.99 11.18 8.52 18.09H9.74a9.52 9.52 0 00-6.23 16.9 12.52 12.52 0 00-2.07 6.84 9.64 9.64 0 003.65 7.7 7.85 7.85 0 00-1.7 5.13 8.9 8.9 0 005.3 8.13 6 6 0 00-.26 1.76c0 6.37 4.2 10.48 10.71 10.48h13.25a73.75 73.75 0 0010.6-.56 35.89 35.89 0 007.58-2.18 17.83 17.83 0 014.48-1.34h1.35c4.69 0 7.79 0 10.5-1 3.85-1.44 6-4.59 6.41-9.38.2-2.46 1.42-4.85 2.84-7.62a41.3 41.3 0 003.42-8.13 48 48 0 001.59-10.79c.1-5.13-1-8.48-3.35-10.55-2.16-1.87-4.64-1.87-9.6-1.88a46.86 46.86 0 01-6.64-.29c-1.92-.94-5.72-4-8.51-6.3l-1.58-1.28c-1.6-1.3-3.27-2.79-4.87-4.23-3.33-3-6.47-5.79-9.61-7.45a20.2 20.2 0 01-6.43-5.53 12.44 12.44 0 01-1.72-5.36 6 6 0 00-6-5.86z"></path></svg></button></span></span><a href="https://github.com/reactjs/reactjs.org/tree/main/content/docs/testing-recipes.md" class="css-1epz0fh">Edit this page</a></div></div></article><div class="css-1kbu8hg"><div><div style="opacity:0;transition:opacity 0.5s ease" class="css-1gf3j5r"><div style="transform:translate(0px, 40px);transition:transform 0.5s ease" class="css-dnl0w7"><nav class="css-7stz2q css-1aai96l"><div><button aria-expanded="false" aria-controls="section_08991759373609944" class="css-1j8jxus"><div class="css-hg8mt2">Installation<svg viewBox="0 0 926.23699 573.74994" version="1.1" x="0px" y="0px" width="10" height="10" class="css-1jiuhrf"><g transform="translate(904.92214,-879.1482)"><path d=" m -673.67664,1221.6502 -231.2455,-231.24803 55.6165, -55.627 c 30.5891,-30.59485 56.1806,-55.627 56.8701,-55.627 0.6894, 0 79.8637,78.60862 175.9427,174.68583 l 174.6892,174.6858 174.6892, -174.6858 c 96.079,-96.07721 175.253196,-174.68583 175.942696, -174.68583 0.6895,0 26.281,25.03215 56.8701, 55.627 l 55.6165,55.627 -231.245496,231.24803 c -127.185,127.1864 -231.5279,231.248 -231.873,231.248 -0.3451,0 -104.688, -104.0616 -231.873,-231.248 z " fill="currentColor"></path></g></svg></div></button><ul id="section_08991759373609944" class="css-14d3mgr"><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/getting-started.html">Getting Started</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/add-react-to-a-website.html">Add React to a Website</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/create-a-new-react-app.html">Create a New React App</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/cdn-links.html">CDN Links</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/release-channels.html">Release Channels</a></li></ul></div><div><button aria-expanded="false" aria-controls="section_06427015371623352" class="css-1j8jxus"><div class="css-hg8mt2">Main Concepts<svg viewBox="0 0 926.23699 573.74994" version="1.1" x="0px" y="0px" width="10" height="10" class="css-1jiuhrf"><g transform="translate(904.92214,-879.1482)"><path d=" m -673.67664,1221.6502 -231.2455,-231.24803 55.6165, -55.627 c 30.5891,-30.59485 56.1806,-55.627 56.8701,-55.627 0.6894, 0 79.8637,78.60862 175.9427,174.68583 l 174.6892,174.6858 174.6892, -174.6858 c 96.079,-96.07721 175.253196,-174.68583 175.942696, -174.68583 0.6895,0 26.281,25.03215 56.8701, 55.627 l 55.6165,55.627 -231.245496,231.24803 c -127.185,127.1864 -231.5279,231.248 -231.873,231.248 -0.3451,0 -104.688, -104.0616 -231.873,-231.248 z " fill="currentColor"></path></g></svg></div></button><ul id="section_06427015371623352" class="css-14d3mgr"><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/hello-world.html">1. Hello World</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/introducing-jsx.html">2. Introducing JSX</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/rendering-elements.html">3. Rendering Elements</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/components-and-props.html">4. Components and Props</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/state-and-lifecycle.html">5. State and Lifecycle</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/handling-events.html">6. Handling Events</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/conditional-rendering.html">7. Conditional Rendering</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/lists-and-keys.html">8. Lists and Keys</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/forms.html">9. Forms</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/lifting-state-up.html">10. Lifting State Up</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/composition-vs-inheritance.html">11. Composition vs Inheritance</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/thinking-in-react.html">12. Thinking In React</a></li></ul></div><div><button aria-expanded="false" aria-controls="section_01848115241002528" class="css-1j8jxus"><div class="css-hg8mt2">Advanced Guides<svg viewBox="0 0 926.23699 573.74994" version="1.1" x="0px" y="0px" width="10" height="10" class="css-1jiuhrf"><g transform="translate(904.92214,-879.1482)"><path d=" m -673.67664,1221.6502 -231.2455,-231.24803 55.6165, -55.627 c 30.5891,-30.59485 56.1806,-55.627 56.8701,-55.627 0.6894, 0 79.8637,78.60862 175.9427,174.68583 l 174.6892,174.6858 174.6892, -174.6858 c 96.079,-96.07721 175.253196,-174.68583 175.942696, -174.68583 0.6895,0 26.281,25.03215 56.8701, 55.627 l 55.6165,55.627 -231.245496,231.24803 c -127.185,127.1864 -231.5279,231.248 -231.873,231.248 -0.3451,0 -104.688, -104.0616 -231.873,-231.248 z " fill="currentColor"></path></g></svg></div></button><ul id="section_01848115241002528" class="css-14d3mgr"><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/accessibility.html">Accessibility</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/code-splitting.html">Code-Splitting</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/context.html">Context</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/error-boundaries.html">Error Boundaries</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/forwarding-refs.html">Forwarding Refs</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/fragments.html">Fragments</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/higher-order-components.html">Higher-Order Components</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/integrating-with-other-libraries.html">Integrating with Other Libraries</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/jsx-in-depth.html">JSX In Depth</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/optimizing-performance.html">Optimizing Performance</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/portals.html">Portals</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/profiler.html">Profiler</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/react-without-es6.html">React Without ES6</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/react-without-jsx.html">React Without JSX</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/reconciliation.html">Reconciliation</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/refs-and-the-dom.html">Refs and the DOM</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/render-props.html">Render Props</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/static-type-checking.html">Static Type Checking</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/strict-mode.html">Strict Mode</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/typechecking-with-proptypes.html">Typechecking With PropTypes</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/uncontrolled-components.html">Uncontrolled Components</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/web-components.html">Web Components</a></li></ul></div><div><button aria-expanded="false" aria-controls="section_05595117830593475" class="css-1j8jxus"><div class="css-hg8mt2">API Reference<svg viewBox="0 0 926.23699 573.74994" version="1.1" x="0px" y="0px" width="10" height="10" class="css-1jiuhrf"><g transform="translate(904.92214,-879.1482)"><path d=" m -673.67664,1221.6502 -231.2455,-231.24803 55.6165, -55.627 c 30.5891,-30.59485 56.1806,-55.627 56.8701,-55.627 0.6894, 0 79.8637,78.60862 175.9427,174.68583 l 174.6892,174.6858 174.6892, -174.6858 c 96.079,-96.07721 175.253196,-174.68583 175.942696, -174.68583 0.6895,0 26.281,25.03215 56.8701, 55.627 l 55.6165,55.627 -231.245496,231.24803 c -127.185,127.1864 -231.5279,231.248 -231.873,231.248 -0.3451,0 -104.688, -104.0616 -231.873,-231.248 z " fill="currentColor"></path></g></svg></div></button><ul id="section_05595117830593475" class="css-14d3mgr"><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/react-api.html">React</a><ul class="css-140tz9x"><li><a class="css-e8rm5m" href="/docs/react-component.html">React.Component</a></li></ul></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/react-dom.html">ReactDOM</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/react-dom-client.html">ReactDOMClient</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/react-dom-server.html">ReactDOMServer</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/dom-elements.html">DOM Elements</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/events.html">SyntheticEvent</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/test-utils.html">Test Utilities</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/test-renderer.html">Test Renderer</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/javascript-environment-requirements.html">JS Environment Requirements</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/glossary.html">Glossary</a></li></ul></div><div><button aria-expanded="false" aria-controls="section_034798681428603984" class="css-1j8jxus"><div class="css-hg8mt2">Hooks<svg viewBox="0 0 926.23699 573.74994" version="1.1" x="0px" y="0px" width="10" height="10" class="css-1jiuhrf"><g transform="translate(904.92214,-879.1482)"><path d=" m -673.67664,1221.6502 -231.2455,-231.24803 55.6165, -55.627 c 30.5891,-30.59485 56.1806,-55.627 56.8701,-55.627 0.6894, 0 79.8637,78.60862 175.9427,174.68583 l 174.6892,174.6858 174.6892, -174.6858 c 96.079,-96.07721 175.253196,-174.68583 175.942696, -174.68583 0.6895,0 26.281,25.03215 56.8701, 55.627 l 55.6165,55.627 -231.245496,231.24803 c -127.185,127.1864 -231.5279,231.248 -231.873,231.248 -0.3451,0 -104.688, -104.0616 -231.873,-231.248 z " fill="currentColor"></path></g></svg></div></button><ul id="section_034798681428603984" class="css-14d3mgr"><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/hooks-intro.html">1. Introducing Hooks</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/hooks-overview.html">2. Hooks at a Glance</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/hooks-state.html">3. Using the State Hook</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/hooks-effect.html">4. Using the Effect Hook</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/hooks-rules.html">5. Rules of Hooks</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/hooks-custom.html">6. Building Your Own Hooks</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/hooks-reference.html">7. Hooks API Reference</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/hooks-faq.html">8. Hooks FAQ</a></li></ul></div><div><button aria-expanded="true" aria-controls="section_027129800028730133" class="css-1j8jxus"><div class="css-1luyeat">Testing<svg viewBox="0 0 926.23699 573.74994" version="1.1" x="0px" y="0px" width="10" height="10" class="css-1mwek35"><g transform="translate(904.92214,-879.1482)"><path d=" m -673.67664,1221.6502 -231.2455,-231.24803 55.6165, -55.627 c 30.5891,-30.59485 56.1806,-55.627 56.8701,-55.627 0.6894, 0 79.8637,78.60862 175.9427,174.68583 l 174.6892,174.6858 174.6892, -174.6858 c 96.079,-96.07721 175.253196,-174.68583 175.942696, -174.68583 0.6895,0 26.281,25.03215 56.8701, 55.627 l 55.6165,55.627 -231.245496,231.24803 c -127.185,127.1864 -231.5279,231.248 -231.873,231.248 -0.3451,0 -104.688, -104.0616 -231.873,-231.248 z " fill="currentColor"></path></g></svg></div></button><ul id="section_027129800028730133" class="css-ts0qly"><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/testing.html">Testing Overview</a></li><li class="css-atv6j6"><a aria-current="page" class="css-1xy1fx4" href="/docs/testing-recipes.html"><span class="css-ifgy4z"></span>Testing Recipes</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/testing-environments.html">Testing Environments</a></li></ul></div><div><button aria-expanded="false" aria-controls="section_027156583680192803" class="css-1j8jxus"><div class="css-hg8mt2">Contributing<svg viewBox="0 0 926.23699 573.74994" version="1.1" x="0px" y="0px" width="10" height="10" class="css-1jiuhrf"><g transform="translate(904.92214,-879.1482)"><path d=" m -673.67664,1221.6502 -231.2455,-231.24803 55.6165, -55.627 c 30.5891,-30.59485 56.1806,-55.627 56.8701,-55.627 0.6894, 0 79.8637,78.60862 175.9427,174.68583 l 174.6892,174.6858 174.6892, -174.6858 c 96.079,-96.07721 175.253196,-174.68583 175.942696, -174.68583 0.6895,0 26.281,25.03215 56.8701, 55.627 l 55.6165,55.627 -231.245496,231.24803 c -127.185,127.1864 -231.5279,231.248 -231.873,231.248 -0.3451,0 -104.688, -104.0616 -231.873,-231.248 z " fill="currentColor"></path></g></svg></div></button><ul id="section_027156583680192803" class="css-14d3mgr"><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/how-to-contribute.html">How to Contribute</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/codebase-overview.html">Codebase Overview</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/implementation-notes.html">Implementation Notes</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/design-principles.html">Design Principles</a></li></ul></div><div><button aria-expanded="false" aria-controls="section_08763750076880301" class="css-1j8jxus"><div class="css-hg8mt2">FAQ<svg viewBox="0 0 926.23699 573.74994" version="1.1" x="0px" y="0px" width="10" height="10" class="css-1jiuhrf"><g transform="translate(904.92214,-879.1482)"><path d=" m -673.67664,1221.6502 -231.2455,-231.24803 55.6165, -55.627 c 30.5891,-30.59485 56.1806,-55.627 56.8701,-55.627 0.6894, 0 79.8637,78.60862 175.9427,174.68583 l 174.6892,174.6858 174.6892, -174.6858 c 96.079,-96.07721 175.253196,-174.68583 175.942696, -174.68583 0.6895,0 26.281,25.03215 56.8701, 55.627 l 55.6165,55.627 -231.245496,231.24803 c -127.185,127.1864 -231.5279,231.248 -231.873,231.248 -0.3451,0 -104.688, -104.0616 -231.873,-231.248 z " fill="currentColor"></path></g></svg></div></button><ul id="section_08763750076880301" class="css-14d3mgr"><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/faq-ajax.html">AJAX and APIs</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/faq-build.html">Babel, JSX, and Build Steps</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/faq-functions.html">Passing Functions to Components</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/faq-state.html">Component State</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/faq-styling.html">Styling and CSS</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/faq-structure.html">File Structure</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/faq-versioning.html">Versioning Policy</a></li><li class="css-atv6j6"><a class="css-e8rm5m" href="/docs/faq-internals.html">Virtual DOM and Internals</a></li></ul></div></nav></div></div><div role="button" tabindex="0" class="css-yx40kw"><div class="css-tctv7l"><div class="css-7ef8f8"><div class="css-1dgtft4"><svg viewBox="0 0 926.23699 573.74994" version="1.1" x="0px" y="0px" width="15" height="15" class="css-sg9l1i"><g transform="translate(904.92214,-879.1482)"><path d=" m -673.67664,1221.6502 -231.2455,-231.24803 55.6165, -55.627 c 30.5891,-30.59485 56.1806,-55.627 56.8701,-55.627 0.6894, 0 79.8637,78.60862 175.9427,174.68583 l 174.6892,174.6858 174.6892, -174.6858 c 96.079,-96.07721 175.253196,-174.68583 175.942696, -174.68583 0.6895,0 26.281,25.03215 56.8701, 55.627 l 55.6165,55.627 -231.245496,231.24803 c -127.185,127.1864 -231.5279,231.248 -231.873,231.248 -0.3451,0 -104.688, -104.0616 -231.873,-231.248 z " fill="currentColor"></path></g></svg><svg viewBox="0 0 926.23699 573.74994" version="1.1" x="0px" y="0px" width="15" height="15" class="css-o1zbu3"><g transform="translate(904.92214,-879.1482)"><path d=" m -673.67664,1221.6502 -231.2455,-231.24803 55.6165, -55.627 c 30.5891,-30.59485 56.1806,-55.627 56.8701,-55.627 0.6894, 0 79.8637,78.60862 175.9427,174.68583 l 174.6892,174.6858 174.6892, -174.6858 c 96.079,-96.07721 175.253196,-174.68583 175.942696, -174.68583 0.6895,0 26.281,25.03215 56.8701, 55.627 l 55.6165,55.627 -231.245496,231.24803 c -127.185,127.1864 -231.5279,231.248 -231.873,231.248 -0.3451,0 -104.688, -104.0616 -231.873,-231.248 z " fill="currentColor"></path></g></svg></div></div></div></div></div></div></div></div></div><div class="css-uygc5k"><div class="css-tctv7l"><ul class="css-15o825x css-lhap5"><li class="css-k2v7we"><div><div class="css-i3b7x6">Previous article</div><div class="css-1gz2d9j"><a class="css-uhcemv" href="/docs/testing.html">Testing Overview</a></div></div></li><li class="css-syjz65 css-14qyarc"><div><div class="css-i3b7x6">Next article</div><div class="css-1gz2d9j"><a class="css-uhcemv" href="/docs/testing-environments.html">Testing Environments</a></div></div></li></ul></div></div></div></div><footer class="css-vn0yrr"><div class="css-tctv7l"><div class="css-ftk3jl"><div class="css-1q9mcvr"><div class="css-12bsqfj"><div class="css-1m3wp4q"><div class="css-krwajx">Docs</div><a class="css-8l81zy" href="/docs/getting-started.html">Installation</a><a class="css-8l81zy" href="/docs/hello-world.html">Main Concepts</a><a class="css-8l81zy" href="/docs/accessibility.html">Advanced Guides</a><a class="css-8l81zy" href="/docs/react-api.html">API Reference</a><a class="css-8l81zy" href="/docs/hooks-intro.html">Hooks</a><a class="css-8l81zy" href="/docs/testing.html">Testing</a><a class="css-8l81zy" href="/docs/how-to-contribute.html">Contributing</a><a class="css-8l81zy" href="/docs/faq-ajax.html">FAQ</a></div></div><div class="css-12bsqfj"><div class="css-1m3wp4q"><div class="css-krwajx">Channels</div><a href="https://github.com/facebook/react" target="_blank" rel="noopener" class="css-8l81zy">GitHub<svg x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="css-6na5q4"><path fill="currentColor" d=" M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0, 0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z "></path><polygon fill="currentColor" points=" 45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8, 14.9 62.8,22.9 71.5,22.9 "></polygon></svg></a><a href="https://stackoverflow.com/questions/tagged/reactjs" target="_blank" rel="noopener" class="css-8l81zy">Stack Overflow<svg x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="css-6na5q4"><path fill="currentColor" d=" M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0, 0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z "></path><polygon fill="currentColor" points=" 45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8, 14.9 62.8,22.9 71.5,22.9 "></polygon></svg></a><a href="https://reactjs.org/community/support.html#popular-discussion-forums" target="_blank" rel="noopener" class="css-8l81zy">Discussion Forums<svg x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="css-6na5q4"><path fill="currentColor" d=" M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0, 0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z "></path><polygon fill="currentColor" points=" 45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8, 14.9 62.8,22.9 71.5,22.9 "></polygon></svg></a><a href="https://discord.gg/reactiflux" target="_blank" rel="noopener" class="css-8l81zy">Reactiflux Chat<svg x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="css-6na5q4"><path fill="currentColor" d=" M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0, 0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z "></path><polygon fill="currentColor" points=" 45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8, 14.9 62.8,22.9 71.5,22.9 "></polygon></svg></a><a href="https://dev.to/t/react" target="_blank" rel="noopener" class="css-8l81zy">DEV Community<svg x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="css-6na5q4"><path fill="currentColor" d=" M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0, 0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z "></path><polygon fill="currentColor" points=" 45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8, 14.9 62.8,22.9 71.5,22.9 "></polygon></svg></a><a href="https://www.facebook.com/react" target="_blank" rel="noopener" class="css-8l81zy">Facebook<svg x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="css-6na5q4"><path fill="currentColor" d=" M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0, 0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z "></path><polygon fill="currentColor" points=" 45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8, 14.9 62.8,22.9 71.5,22.9 "></polygon></svg></a><a href="https://twitter.com/reactjs" target="_blank" rel="noopener" class="css-8l81zy">Twitter<svg x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="css-6na5q4"><path fill="currentColor" d=" M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0, 0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z "></path><polygon fill="currentColor" points=" 45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8, 14.9 62.8,22.9 71.5,22.9 "></polygon></svg></a></div></div><div class="css-12bsqfj"><div class="css-1m3wp4q"><div class="css-krwajx">Community</div><a href="https://github.com/facebook/react/blob/main/CODE_OF_CONDUCT.md" class="css-8l81zy">Code of Conduct<svg x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="css-6na5q4"><path fill="currentColor" d=" M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0, 0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z "></path><polygon fill="currentColor" points=" 45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8, 14.9 62.8,22.9 71.5,22.9 "></polygon></svg></a><a class="css-8l81zy" href="/community/support.html">Community Resources</a></div></div><div class="css-12bsqfj"><div class="css-1m3wp4q"><div class="css-krwajx">More</div><a class="css-8l81zy" href="/tutorial/tutorial.html">Tutorial</a><a class="css-8l81zy" href="/blog">Blog</a><a class="css-8l81zy" href="/acknowledgements.html">Acknowledgements</a><a href="https://reactnative.dev/" target="_blank" rel="noopener" class="css-8l81zy">React Native<svg x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="css-6na5q4"><path fill="currentColor" d=" M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0, 0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z "></path><polygon fill="currentColor" points=" 45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8, 14.9 62.8,22.9 71.5,22.9 "></polygon></svg></a><a href="https://opensource.facebook.com/legal/privacy" class="css-8l81zy">Privacy<svg x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="css-6na5q4"><path fill="currentColor" d=" M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0, 0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z "></path><polygon fill="currentColor" points=" 45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8, 14.9 62.8,22.9 71.5,22.9 "></polygon></svg></a><a href="https://opensource.facebook.com/legal/terms" class="css-8l81zy">Terms<svg x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="css-6na5q4"><path fill="currentColor" d=" M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0, 0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z "></path><polygon fill="currentColor" points=" 45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8, 14.9 62.8,22.9 71.5,22.9 "></polygon></svg></a></div></div></div><section class="css-1ac8j74"><a href="https://opensource.facebook.com/projects/" target="_blank" rel="noopener"><img alt="Facebook Open Source" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAVQAAABaCAMAAADQMV5DAAAC3FBMVEUAAAD///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////+GTFYVAAAA9HRSTlMAG7O/KQR48v/+hA5W2+piObG8RBSU/fehIG7stSWl9nkIStbYU0XN4FUvrHoDcOi3OAuLmheOmRVm4rtBNbDucsnfXlDUJpuGB3vtM3+mHBKMEF3FSDzmaMLpWN7PRh2XkAaAo3X4riuiBctS3WAxtvFxEWTkxD4YbKirjzr7H/W5MIHKvrKtyCh3AUsNuKnHaxNOzPlMqqTGn++vniOTCSJJzhZAfKfAhSEuLWU/jSyDwU9DiJY3X9JzujJRRwIewzRnhzZZtFpNkldcvSRbPVQ7KicMDxoZkXagidWCb20K2dflYZ2KleGc0WrQ2vD8mH5p7f+VowAADPFJREFUeAHs0AN7Y2EYhOGJbVu1bdu22+3axp/fYurGyeX3PvZ3HuRFoVSpUU5Co9Xp9QajCaJszBb9NasN5SHsDv0dpwuidG4Pc3p93PoDKJEIhtgyHFFEuReLJ1ACkUwxZEUlLlVV86imFsUSdfWMqGtoBDU180xLK4oh2tr11NH54GSXnrp7UDDR28d6/QN4ZHCI54dHUBgxMMp0Y+N4ZmKS11ITEPmbmmY238ws0pmb5/X6BYj8NC7qaWkZGaxM62l1DSIP6xb22thEFlv9vGt7ByIX+y5j7fUih/0D3nl4BJHN8YmeTleQ09mLGG8+n4LI6OUrVnr9BnlRvNWT8R1EWuZDFnr/AXnbVPGZj58gnvv8hXm+fkM63yNTPUjnx08+9+s3xGOd7Xo6+YPnFv6u/rto1z6A28buPI7/7rBK/nPrXuaCnFaTlcej8eqC9CpbN6KxfcFk30pO4SFVinQjD73VReIWw0XyWc2RL+ICWHtN+1kuKe7l3L1nuvvikmx6771Mr8c8yhhAwAmUwCxT+HHlGzyXr0EP+fivfLwzpTwLvzsffW5k6/NwKXvjCySsNOAnr2pcvWZtV9f0Gau7H10Hv7taSXjuP9djRFnPahImL4Rf79S+7s54R1dlZWtHvH+gbsNn4Te4kYQ5CZQJbyDhvx5CgM8NbVybjs94sdI01zau6Wiur2mdhAArLBLq8Wen2pgAWZLxGiLhpU3wW/Du1Sur0m9t3/y5+15+eUvm0YG6dNXjWz+xDH7bNpOAsenkNqE8GmECOHG8hp4hoqWL4Ld8+9Klw812zfSE8zSvrcndtzsadu6C3+7HiegZjI0kzcX4m476efh8KlnfXpvu6J7R8i447lzR19CfHuru+0IvfGYVElWD199w1C9itI/9x9bK5viahi/tgceWvd374um1NZ37MdoeT9Ry1AOj+xxcPaMqXbn6pWr48EMb+9JVK1d/8jC87ilHHSvq+z4y0JHuan/8CAIlWrfWNw8vHWgpUlSW1DSVAZCZs6RqSQMOOaklZU9UruVXHIxrigH/ij8qk0sR9dNH69PxpTse+gAQbNZ/H+vOVb/3HcWIykwSNAbbhmBIZEkxsjR2+2FMskjiTlTVEltMhhGGTSR2BK14ozLdLkHUD8/paH5rzewlGMO6dzQcSw8f3R49qhGzNBmQFUtnkiSWkiQZAOQU6fLthyJtciSqmd+iWZYBzw7N0pl/xROV6Tp77aMeb+9q3tF6AiFO9n+kuf/oyYhRnb+j+Fk+qkoK8gxLAwwykWdasoiq3G4p6xbL79CcHXrwiogarWmEqKfMHc3H1p5GqKeqpHRdvCJiVE2EEliMJADMsuEmSXAuMEVUMpAngnt3GKQFroio0ZpGiLps9fBQwz0owOl9drxmcJxR3VQAVgoOVURVSIaLIS7LU4gBGmlwmDR6h2n5V5yoomkJorY0xM88BK/eLW1nz35+E4PXKw3xpf9TeFTfOyoGcDIAhyV57kxBI3dgDmiuLaKVd4cavCIuFE1LELXiPSv7G4/DjZ3bn01MmpTInnjbLLjJdbX19dsiPP09yURP/yW2zgWBNO+W/NWWZwcpASsiKtNJRiminj7funaYweW+eRcGM9U5mYuJRBvcLh3r33H2zxxVIjclKCppYSsiKtN1SypJ1Pse73r8/grAseex/U2ZE5dzFmeaBq94buJVOzqvHo8UVSE2OqqVGnWnws0XVQFi7h0seIWTqutMJbMUUTedb600X4Zj02MXm/ZnZ+6+dm3P/Kza1HPkDsDxT1LnjCWRohqkwsFIAmDH/Nm9UTkcKhliR+gKJ/HSSqFk6aP2ztvftHjuulPIWX9tcG7T4GUGx87IUWFJrn4iapK4N3tydFQTDjM2eocUvMJJZ2IDGSWPevx/m/bPfS9GsMVqU/bLRYzquXUMK184pjNnyQBsy3nIDBHVSnqKe3aopPpXPC/+LbnEUd8+OJi5cA2Of0hU91z/YDGjQrqdiFuaJIlSrveaKYBZuuy8gRJRk2KLuFLCqB2WGbTiRBW/HCtt1OezmRMz4XLjeiZ7X1GjMomkJOdJm1KQbjeyNA6WlCglHupWioPxFIm6GiEptqgmSQyuHbJqix1BK05UGJZZ2qg3E9WJm3C5lq2etCBCVF2FT1KnHIkDKRsC02KUY3PkKeIKPSkeqDFxBJUTEwuuHZbYEbgiW4bz+1mljfrIpOrENbgsv95zfVGEqMFkzhm8GDfgZhjw4lwevUNG2IqjlFHP5qJu8oyyhEYtC4u6J1GdXQeXTbmn/7ly1EhR5Wxm8XzPUPC86uyt6FEZ5xzFxDmX/1qifkW9mLkgw7Et0dMzaVbEqHIqlp/BVliRitr0J7GU/FcRFQuyGVVlzsvWi4ubLnNEi6pYlpnknCsSWSqKIEW6wjlPmkTaX0XUryYGT849sQvCBy7Oa7qY/Wy0qCaZDHlcpyQiS5KCPNkm5a8hKm5d6WlSLy+649Wv3Xp20uKm6oW7Ix2oIOXuyMwiVI3ZcBgMBSj90d+ShYNN1dcvX8997Wm6+Ni00Ud/j4wrqkoa3KK/EzdIRQQlOqTeMy/Rk6nu6anO9FxOLIHb148NSeM7pI5J8JDJdOYb/AMShiKGLAQxaMEVjbPw0RPfbIUBh8ycBaZqLGx0oyhRK+7v619qwG3WsuvZSdevT8pO4l+D2+m6Wnv68vFE5aTCyyQGQLMCBiTUGOkSkSmLR7b9pwVJIkp5ssqkwMc3SWHgNslGjqUAmkXEw0Y3ihIV3+iOn3kdvN5739lFi87dehe8nu6Of2R8H/ylLP+zNxk8IAGTUrJIm1+QpJHDKcXS4SZZBhwhkxTO54qkwSRTlUNHN4oTdf7G4c6GNhTg1X12la6OK6pkYzRLCx6QUCjpDFmIrSJuPpEGR/48isERPEnhj5qyOMJHN4oUtcJck65r/ThCsW/uSB8bfnBcUUnzd5YQPCCheW9m587xfeBiSES2xiEET1L4o4r7O3x0o0hRsUCvbd5nfwwhlg2dae6fk0GRovoHJJj3sz+JXM9uAx7cjBGRLaoHT1L4oorfMHx0o1hRseHe3IBa+7cMjOHWqsa6dHyrhmJEDRuQUMiJ4VwwmqymYhQT64GTFL6oIlj46EaxouKBe+ubO5Yufd17EQy9b7zaPdTc9e1LEKL+nxo4IGFyh0I8LKqgxkhF8CSFL6r4Pnx0o3hRsWLHi8NVte32hTcjyOLhGrsq/pGlb6oYb1TTCn7t7o9KHkZBUcFiMQRPUviiimvCRzeKGBW7L23Mjae/deM3vwifw4dqjuXG0ze+c9r4x9NVSsIrZTF/VMU3UlFYVCTJCJ6kCI4aOroRKep8jKZ+s+Yf03Hpxe+0wWPLmxr3xdP17f0JjPb5Qt5RxeDBLBPBAxL6RKJy4v5JCu8G3RM1ZHQjUtR18Kn4wlvba5uHGqTvMjgefF9dQ2d6aGDN974PH1bQe/+UN5XFggckFJInEFUl2T9J4XnXxcgTNWR0I1LUlW+D3y5tx5l42t46NHc98nqaa6ZXVe1ofOAm/Nr6C4gKkxTPIxUIHJBgrlMCWR4jqiQxT8LA2QpdxwjNGzVkdGPCSPj6LPide0/Nyqp0X83sk/Ldd3/8wJfaZ1SlH9ffwOH34E4SEF7VlpEnS6Jf8IAEd04BuGWPETVJMdXzbxQ0W6GScnvB+/QPGd2YsH4SpqxAgHnD7fXpeF3jdNO0l64ZTnfVdB15M/ySMRLOI5RGlD/5tynGIQQOSKhWTDHEOITJxogqDkBSKudciVEycJJC5DY5wE3LkDxRQ0Y3Ju76D0j4YQ/8vr9hTXdnVYddWWl3VA0N7GiZBb8vD5Dwox9jYp9RaRQ0IJFyj1SIQQvfYITAbYucK4MmKZyJDVNGykROfjAjdHQjglPbX09CRxv87th7pv2Y3TnUtbJ96TuWwG/XT0h47uCdwMQ+TdUoeEACzkL4OAYPm6TwjmeEj25Ete0lyvvp3fBb0PKz6TPWnP/Ev95AgO3PkTB0FyZMI/wtmjmDhJ8/jSAfv2fJrvUIkJ1DwsB+oBzV58i/k9BwAAU7d4yEf/kegpSj4lM7P0PCL9ahIK9+kvI2z0I0agx/s+QhyltVgXBPfoaEx9tQNpbMAAmTryCEupWEX15HWZhXppCw420YQ9taEl5oQQHKPvhuypv96v97yU8p7/7nUZiym10k/PM3EOhX/0ZC3WEUruzEVhJ+fR0+TWdI+M2PMT5lLb8lodKAx7U4Cb9bhXEr+9rvKe9b2+D4yh9+R0LzXZiIsuPHSHj9BoxY+BYSBpZhosqu/IaE7owYn6gj4Zk/oiwC5wiq9r3f/wXlHXwZZdFs+iYJD3+IhM7dKIvuxkfIofegrDj++HMSPtqCsqKp+JY44Hs7yorp5rHGZ1Gosv8DnDgXp7vdFQUAAAAASUVORK5CYII=" class="css-1izr7si"/></a><p class="css-1yy5aal">Copyright © 2024 Meta Platforms, Inc.</p></section></div></div></footer></div></div><div id="gatsby-announcer" style="position:absolute;top:0;width:1px;height:1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border:0" aria-live="assertive" aria-atomic="true"></div></div><script> if(true) { (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) })(window,document,'script','https://www.google-analytics.com/analytics.js','ga'); } if (typeof ga === "function") { ga('create', 'UA-41298772-1', 'auto', {}); }</script><script id="gatsby-script-loader">/*<![CDATA[*/window.pagePath="/docs/testing-recipes.html";/*]]>*/</script><script id="gatsby-chunk-mapping">/*<![CDATA[*/window.___chunkMapping={"polyfill":["/polyfill-f9ab87d63a72ccea1bfc.js"],"app":["/app-91f91e569a673dd999c0.js"],"component---src-pages-404-js":["/component---src-pages-404-js-92c2a65be775096bc9c7.js"],"component---src-pages-acknowledgements-html-js":["/component---src-pages-acknowledgements-html-js-6e2d97a03ca0d5ec9f68.js"],"component---src-pages-blog-all-html-js":["/component---src-pages-blog-all-html-js-41641284b9aa8be80dad.js"],"component---src-pages-docs-error-decoder-html-js":["/component---src-pages-docs-error-decoder-html-js-1a7e9a78b60acee11aee.js"],"component---src-pages-index-js":["/component---src-pages-index-js-930dfb5a04d8b931c22d.js"],"component---src-pages-jsx-compiler-html-js":["/component---src-pages-jsx-compiler-html-js-89bc00c51aa6f8ec0057.js"],"component---src-pages-languages-js":["/component---src-pages-languages-js-1f7876e4ee14191d20e0.js"],"component---src-pages-versions-js":["/component---src-pages-versions-js-5aca965f77a65c90c0b7.js"],"component---src-templates-blog-js":["/component---src-templates-blog-js-49b8489e4e6b0081b93a.js"],"component---src-templates-codepen-example-js":["/component---src-templates-codepen-example-js-2c3fbc22c12fd23f610b.js"],"component---src-templates-community-js":["/component---src-templates-community-js-628af1a6d727eb0b67e7.js"],"component---src-templates-docs-js":["/component---src-templates-docs-js-f436a098b1c76995b750.js"],"component---src-templates-tutorial-js":["/component---src-templates-tutorial-js-007546471d422fc49538.js"]};/*]]>*/</script><script src="/polyfill-f9ab87d63a72ccea1bfc.js" nomodule=""></script><script src="/component---src-templates-docs-js-f436a098b1c76995b750.js" async=""></script><script src="/1ed44328c19c4a4d76fd533f20afa4a4705f4d6f-d0e6caf9a2a8d7af058f.js" async=""></script><script src="/3e8f09252b6028beb8baf8cc63801156f5861675-41a2442ed6f07195fa74.js" async=""></script><script src="/commons-7c52edc1944d43f8385f.js" async=""></script><script src="/app-91f91e569a673dd999c0.js" async=""></script><script src="/styles-4c7d46604086483aa196.js" async=""></script><script src="/framework-5e497f6bfe92c60d1ebf.js" async=""></script><script src="/webpack-runtime-553c85249a68a5037bdb.js" async=""></script><script src="https://unpkg.com/docsearch.js@2.4.1/dist/cdn/docsearch.min.js"></script></body></html>