<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jake Dowie</title>
    <description>The latest articles on DEV Community by Jake Dowie (@jake_dee).</description>
    <link>https://dev.to/jake_dee</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F650997%2F05b791b0-462a-4959-8b65-85ee380927dd.png</url>
      <title>DEV Community: Jake Dowie</title>
      <link>https://dev.to/jake_dee</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jake_dee"/>
    <language>en</language>
    <item>
      <title>Password Security in 2022 - What you need to know</title>
      <dc:creator>Jake Dowie</dc:creator>
      <pubDate>Fri, 24 Sep 2021 13:57:49 +0000</pubDate>
      <link>https://dev.to/jdlt/a-complete-guide-to-password-security-in-2021-259h</link>
      <guid>https://dev.to/jdlt/a-complete-guide-to-password-security-in-2021-259h</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;92% of UK businesses experienced a cyberattack in the last 12 months&lt;/p&gt;

&lt;p&gt;(Keeper 2021 UK Cybersecurity Census)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In this age of hacking and cyber-terrorism, your company's data is a target. And it doesn't take much for a hacker to break into a network and wreak havoc. The stakes are high. What do you need to know about password security?&lt;/p&gt;

&lt;p&gt;This blog post will cover (almost) everything that those with responsibility for IT should know about passwords - from the basics to the latest trends in protection. We'll give you all the information necessary so that you can make informed decisions when it comes to protecting your company's assets from hackers and other threats.&lt;/p&gt;

&lt;p&gt;While this guide is aimed at those responsible for an organisation’s IT security it’ll hopefully be useful to anyone interested in password security or those just trying to understand why so much emphasis is put on their company’s IT security policy.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;23,000,000 account-holders in the UK use the password “123456”&lt;/p&gt;

&lt;p&gt;(Nord Pass, 2020)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Why password security is important
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;65% of UK businesses relaxed their cybersecurity polices during the pandemic&lt;/p&gt;

&lt;p&gt;(Keeper 2021 UK Cybersecurity Census)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Hopefully this will be pretty obvious so I won’t go on about it, but it can’t hurt to briefly run through it again…&lt;/p&gt;

&lt;p&gt;Passwords have been with us for a very long time and will likely be with us for quite a while longer. Despite their obvious flaws, they’re still ubiquitous.&lt;/p&gt;

&lt;p&gt;Passwords and usernames/email addresses (credentials) are often the first line of defence between your organisation’s sensitive data and the army of cyber-criminals trying to access it.&lt;/p&gt;

&lt;p&gt;Gaining access to precious corporate data using credentials found via social engineering (mechanisms such as &lt;a href="https://en.wikipedia.org/wiki/Phishing"&gt;phishing&lt;/a&gt; and &lt;a href="https://en.wikipedia.org/wiki/Phishing#SMS_phishing"&gt;smishing&lt;/a&gt;) is still the most common cause of data breaches.&lt;/p&gt;

&lt;p&gt;The risks to your organisation of a data breach are not only related to the sensitivity of your data were it to get into the wrong hands. With the rise of ransomware, you also need to consider the implications of losing access to your own data.&lt;/p&gt;

&lt;p&gt;Weak passwords and poor password security can effectively leave the door open to cyber-criminals so if IT security is your responsibility you can’t really afford to ignore it! It’s also one of the simplest things to fix in the often highly complex world of IT security.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It takes less than a second to crack 8 of the top 10 most used passwords&lt;/p&gt;

&lt;p&gt;(Nord Pass, 2020)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  How to improve password security
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;29% of adults worldwide rotate between 5 and 10 different passwords&lt;/p&gt;

&lt;p&gt;(Proofpoint, 2020)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There are lots of ways to increase the password security of your organisation. Some of them require quite a bit of technical knowledge to implement but there are also some pretty simple ones too. Most of them are relatively cheap to implement, at least compared to the potential cost of a security breach!&lt;/p&gt;

&lt;h2&gt;
  
  
  What does a strong password look like?
&lt;/h2&gt;

&lt;p&gt;A relatively fundamental thing is to first understand what makes a good password.&lt;/p&gt;

&lt;p&gt;A strong password follows a couple of simple rules. It should:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Be of a sensible minimum length&lt;/li&gt;
&lt;li&gt;Contain a mix of lowercase and uppercase letters, numbers and symbols&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;A password of 15 numbers can be cracked in around 6 hours.&lt;/p&gt;

&lt;p&gt;(howsecureismypassword.net)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A minimum of 16 characters is usually recommended for a secure password which should take at least 2 days to crack in a brute-force attack. If it contains a mix of upper and lower-case letters, numbers and symbols it’ll take up to 1 trillion years!&lt;/p&gt;

&lt;p&gt;Ideally the restrictions placed on a password should be flexible enough to accommodate different types of passwords. For example, some people may find a password made up of a few random words easier to remember than a much shorter string of random characters. If a password is of significant length, the use of special characters becomes less relevant. An 18-character password of just lower-case letters will take around 23 million years to crack!&lt;/p&gt;

&lt;p&gt;All of this may not seem relevant if you are going to implement a password manager but remember each user will still need a secure master password.&lt;/p&gt;

&lt;p&gt;Data from &lt;a href="https://howsecureismypassword.net/"&gt;https://howsecureismypassword.net/&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“password” is the 4th most common password used&lt;/p&gt;

&lt;p&gt;(Nord Pass 2020)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Password managers
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;16% of adults worldwide use the same one or two passwords for all accounts&lt;/p&gt;

&lt;p&gt;(Proofpoint, 2020)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In case you’re not aware, password managers are SaaS products that manage the ever-increasing list of credentials most of us use in our working (and personal) lives.&lt;/p&gt;

&lt;p&gt;When it comes to password managers, something is better than nothing. A basic password manager will mean that you don’t have to remember your credentials and in-built password generators can easily generate new secure passwords when required.&lt;/p&gt;

&lt;p&gt;These days they will also often tell you if your credentials have been leaked in a security breach and prompt you to change the related password.&lt;/p&gt;

&lt;p&gt;There are plenty of password management options out there, but they generally fall into two categories:&lt;/p&gt;

&lt;h2&gt;
  
  
  In-browser password managers
&lt;/h2&gt;

&lt;p&gt;Although browser-based password managers are improving, they generally don’t have a lot of the really useful features of many 3rd party products.&lt;/p&gt;

&lt;p&gt;They often have significant disadvantages over 3rd party products such as the fact that they lock you in to a particular browser. If you regularly switch browsers, for example if you use Chrome on Windows and Safari on your iPhone this kind of solution probably won’t work for you.&lt;/p&gt;

&lt;p&gt;There are other features that you usually miss out on when using a browser-based password manager which are covered in the next section:&lt;/p&gt;

&lt;h2&gt;
  
  
  3rd party password managers
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Cross platform and browser&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're going to use a password manager you really want one you can use across all your devices. It's a pain finding you've generated a highly secure, reandom password, saved it to your password manager but can't access it on your phone!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ability to share passwords&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Despite it generally being bad practice, it may be necessary to have some passwords which are shared. For instance passwords for emergency accounts. Password managers often come with the ability to share credentials between accounts, often without even revealing the password to the person you're sharing it with, maintaining security.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Auditable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Many of these platforms allow managers to audit their team's use of the software, seeing if they're reusing passwords, have insecure passwords, or even if they're not using the software at all!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enforcement policies/rules&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Many rules can be specified which maintain a level of security. For example, prohibiting exporting data, or the reuse of master passwords, or requiring a unique master password.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Share credentials across sites&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Credentials that are used across multiple sites can have their credentials easily shared without creating duplicates.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add notes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It may be useful to be able to add notes to accounts, for instance if an account requires a password which needs to be quoted over the phone.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One-click change of credentials&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some password managers allow the credentials for specific sites to be changed with a single click.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; It’s worth mentioning that a password manager is only as secure as the master password used to access it. So, it’s &lt;em&gt;really&lt;/em&gt; important that if your organisation uses a password management solution you set out some clear rules around master passwords, or even better, setup rules to enforce those policies.&lt;/p&gt;

&lt;p&gt;These should include policies like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No re-use of master passwords&lt;/li&gt;
&lt;li&gt;Master passwords shouldn’t be written down&lt;/li&gt;
&lt;li&gt;Master passwords should have minimum complexity rules making them more difficult to crack&lt;/li&gt;
&lt;li&gt;MFA should be mandatory on password management tools&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;In a recent Microsoft Twitter poll, one in five people reported they would rather accidentally “reply all”—which can be monumentally embarrassing—than reset a password.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Multi-factor authentication (MFA)
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;20% of remote workers in the UK use their work email and password to log into consumer websites and apps&lt;/p&gt;

&lt;p&gt;(Proofpoint, 2020)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is the second most important step in securing your users’ logins and is usually pretty simple to implement. It’s also sometimes referred to as two-factor authentication (2FA).&lt;/p&gt;

&lt;p&gt;The way this works is by requiring at least two authentication mechanisms (factors) before granting access to a resource. This means the user must be in possession of not just the relevant credentials, but also another piece of information which is not easily accessed.&lt;/p&gt;

&lt;p&gt;Username/password credentials are usually the first factor and the 2nd factor can be one of a few things. The most common 2nd factors are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An SMS message with a unique code&lt;/li&gt;
&lt;li&gt;An email with a unique code&lt;/li&gt;
&lt;li&gt;A unique code generated by an app (usually on a mobile phone)&lt;/li&gt;
&lt;li&gt;A USB or NFC hardware device the user has access to&lt;/li&gt;
&lt;li&gt;Biometric verification from a mobile device (e.g. facial recognition or a fingerprint scanner)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A lot of security-conscious software will have MFA built-in these days. In some cases it’ll just be a matter of turning on this feature. However, it’s becoming more common to have this feature turned on by default, or even mandatory given how much additional protection it can give.&lt;/p&gt;

&lt;p&gt;MFA setup can be more complicated depending upon the types of factor supported. Some users can also find It a bit of a pain as it can require registering a separate device and can often increase the time it takes to login to a system. However, given the significantly increased level of security and peace of mind MFA can give to those with responsibility for an organisation’s security it’s often worth the trouble.&lt;/p&gt;

&lt;h1&gt;
  
  
  Single sign-on
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;88% of consumers across the world use the same password for more than one account&lt;/p&gt;

&lt;p&gt;(Auth0, 2021)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Single sign-on (SSO) enables your users to use a single password to access multiple accounts.&lt;/p&gt;

&lt;p&gt;The primary benefit of SSO to your users is that the number of credentials they need is reduced. There are also multiple benefits to your organisation of this approach.&lt;/p&gt;

&lt;p&gt;The idea is that you allow a single provider to manage the login for multiple systems. For example, if you use Microsoft Active Directory (AD), you can use this solution to grant your users access to other corporate resources. These can be any corporate resources that support SSO, such as Google, Apple, Salesforce, Zoom and plenty of others.&lt;/p&gt;

&lt;p&gt;This takes a bit of setting up but once you get the hang of it it’s not too difficult, and importantly it saves your users hassle and increases security.&lt;/p&gt;

&lt;p&gt;An additional benefit of SSO is that if your user forgets their password, or leaves, IT have a single place to reset the password or disable the user account.&lt;/p&gt;

&lt;p&gt;Having a single mechanism of authentication for multiple systems also makes user onboarding and offboarding significantly simpler for obvious reasons.&lt;/p&gt;

&lt;h1&gt;
  
  
  Passwordless authentication
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;“123456” is the most common password in use&lt;/p&gt;

&lt;p&gt;(Nord Pass 2020)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The death of the password has been predicted from as far back as 2004 by Bill Gates, and it’s been predicted many times by many others since then.&lt;/p&gt;

&lt;p&gt;However, it’s not until relatively recently that major authentication providers have embraced passwordless technologies.&lt;/p&gt;

&lt;p&gt;Passwordless login is similar to MFA in the sense that it uses multiple factors to authenticate a user. The key difference is that it doesn’t require a password. It usually uses public-key cryptography to identify and authenticate a user. Basically, this means that the user provides their public identifier (email address, phone number, or username) and at least one other factor (containing their private key) to identify and authenticate them.&lt;/p&gt;

&lt;p&gt;Significantly, in March 2021 Microsoft made passwordless sign-in generally available to commercial users. They have since (September 2021) made passwordless sign-in generally available to all users.&lt;/p&gt;

&lt;p&gt;This may well signal the beginning of the end of the road for passwords, we’ll have to wait and see! Either way, passwords will certainly be with us for a while longer.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;64% of UK organisations that have experienced a cyberattack in the last 12 months have between 1 and 100 employees&lt;/p&gt;

&lt;p&gt;(Keeper 2021 UK Cybersecurity Census)&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>password</category>
      <category>security</category>
    </item>
    <item>
      <title>React component testing with Jest and React Testing Library</title>
      <dc:creator>Jake Dowie</dc:creator>
      <pubDate>Tue, 07 Sep 2021 11:07:13 +0000</pubDate>
      <link>https://dev.to/jdlt/react-component-testing-with-jest-and-react-testing-library-234k</link>
      <guid>https://dev.to/jdlt/react-component-testing-with-jest-and-react-testing-library-234k</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fst1vviwju1cx022bnd1s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fst1vviwju1cx022bnd1s.png" alt="Interface experiments"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Testing React components gives you confidence a component will work when the user interacts with it. As a junior full-stack developer on my first job, I found it extremely useful in helping me understand our current codebase as well as allowing me to add value while learning.&lt;/p&gt;

&lt;p&gt;This article is a summary of the information I found useful during my research and the answer to some challenges I came across. I don't hope to re-invent the wheel but to help others in a similar stage of their career. It's also assumed that you have &lt;em&gt;some&lt;/em&gt; experience in writing tests.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why &lt;a href="https://jestjs.io/" rel="noopener noreferrer"&gt;Jest&lt;/a&gt; and &lt;a href="https://testing-library.com/docs/react-testing-library/intro/" rel="noopener noreferrer"&gt;RTL (React Testing Library)&lt;/a&gt;?
&lt;/h3&gt;

&lt;p&gt;React openly recommends Jest as a test runner (perhaps because they maintain it) and RTL as their testing utility of choice. Jest testing is very fast, it's easy to set up and it has many powerful features such as mock functions which allow you to replace a specific function and return a desirable value or to check how the test subject is executing the function. RTL is very simple to set up, easy to make queries (including asynchronously) and because of how it was built, it'll help you write good tests.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://testing-library.com/docs/ecosystem-jest-dom/" rel="noopener noreferrer"&gt;Jest-Dom&lt;/a&gt; is not required but makes writing tests much easier because it extends Jest matchers (methods that let you test values in different ways e.g. &lt;code&gt;toBe()&lt;/code&gt;, &lt;code&gt;toHaveBeenCalled()&lt;/code&gt;) and allows you to write clearer tests.&lt;/p&gt;

&lt;p&gt;Another popular tool is &lt;a href="https://enzymejs.github.io/enzyme/" rel="noopener noreferrer"&gt;Enzyme&lt;/a&gt;, but many believe that it can lead to bad testing practices. The main concern is that Enzyme offers extra utilities that allow you to test the internal workings of a component (e.g. read and set state of the component). The team at React tests React; therefore, there is no need for you to test React’s functionality such as state, &lt;code&gt;componentDidMount&lt;/code&gt;, etc. The same goes for other libraries you may use.&lt;/p&gt;

&lt;h3&gt;
  
  
  What to test?
&lt;/h3&gt;

&lt;p&gt;When component testing in React, the focus should be on replicating how the user would interact with the React component. This means that we should test for what the user should or should not see, and how they are meant to interact with the app once it renders (e.g. that the value of a search/input field can be changed) instead of testing implementation (e.g. was &lt;code&gt;componentDidMount&lt;/code&gt; called x number of times).&lt;/p&gt;

&lt;p&gt;Some good questions to ask yourself when writing tests are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What does the component render? Also, does it render differently under different conditions?

&lt;ul&gt;
&lt;li&gt;This is what the user will see and potentially interact with. By thinking about it, you will also realise that users should access and see different information depending on certain conditions being met&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;What happens when the user interacts with the component?

&lt;ul&gt;
&lt;li&gt;These are the parts of the app which the user will click, write into, etc. and they’ll expect something to happen. Tests should be written to prove that whatever is meant to happen does so when the event is triggered!&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;When a function is passed in as a prop, how does the component use it?

&lt;ul&gt;
&lt;li&gt;You may need to recreate the behaviour of this function by using the Jest mock concept to know if the function has been called and the correct values were used&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  How to write a test?
&lt;/h3&gt;

&lt;p&gt;So, onto the interesting part, how to test React components with Jest...&lt;/p&gt;

&lt;p&gt;RTL’s most used functions are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;render&lt;/code&gt; – which renders the component&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;cleanup&lt;/code&gt; – which unmounts the React DOM tree that was mounted with &lt;code&gt;render&lt;/code&gt;, and&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;fireEvent&lt;/code&gt; – to fire events like a click.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Jest's most used functions are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;expect&lt;/code&gt; along with a matcher&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;jest.fn()&lt;/code&gt; to mock a function directly&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;jest.spyOn()&lt;/code&gt; to mock an object method, and&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;jest.mock()&lt;/code&gt; for an entire module.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The test should be structured as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Declare all &lt;code&gt;jest.fn()&lt;/code&gt;/&lt;code&gt;spyOn()&lt;/code&gt;/&lt;code&gt;mock()&lt;/code&gt; with or without mocked implementations&lt;/li&gt;
&lt;li&gt;Call RTL’s &lt;code&gt;render&lt;/code&gt; function with the test subject as an argument – provide context whenever the component consumes a context. Also, if React-Router Link is used in this component, an object with a property wrapper and value MemoryRouter (imported from React-Router) must be passed as the second argument. Optionally wrap the component in MemoryRouter tags&lt;/li&gt;
&lt;li&gt;Query the React DOM tree by using RTL’s query functions (e.g. &lt;code&gt;getByRole()&lt;/code&gt; ) and check the values by call&lt;/li&gt;
&lt;li&gt;Check values queried by calling &lt;code&gt;expect()&lt;/code&gt; along with the relevant matcher. To replicate user interaction use &lt;code&gt;fireEvent&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;RTL also returns a &lt;code&gt;debug()&lt;/code&gt; method when render is called. Debug is fantastic for checking what is rendered in the React tree for situations like debugging your tests.&lt;/p&gt;

&lt;p&gt;We will use the code below (a search field) as our example of a React component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;render&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;validateSelection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;minCharacters&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;inputFluid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;inputLabel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;clear&lt;/span&gt;
  &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;icon&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;validateSelection&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Icon&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"check"&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"green"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Icon&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"search"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Search&lt;/span&gt;
      &lt;span class="na"&gt;minCharacters&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;minCharacters&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isLoading&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;icon&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;onResultSelect&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onResultSelect&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;onSearchChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onSearchChange&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;results&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;clear&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;fluid&lt;/span&gt;
      &lt;span class="na"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;placeholder&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;fluid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;inputFluid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;inputLabel&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Above we are destructuring props and state. We are also returning a &lt;a href="https://react.semantic-ui.com/" rel="noopener noreferrer"&gt;Semantic UI React&lt;/a&gt; &lt;code&gt;Search&lt;/code&gt; module. In essence, the above will render an input field. When changed, it will call &lt;code&gt;onSearchChange&lt;/code&gt; and Semantic UI React will automatically pass two arguments, &lt;code&gt;event&lt;/code&gt; and &lt;code&gt;data&lt;/code&gt; (all props, including current value). One of &lt;code&gt;onSearchChange&lt;/code&gt;’s jobs is to call an API and return results that match the current value.&lt;/p&gt;

&lt;p&gt;Below are the tests we built for this component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@testing-library/jest-dom/extend-expect&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cleanup&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fireEvent&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@testing-library/react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;SearchField&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./SearchField&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="nf"&gt;afterEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cleanup&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;useFakeTimers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;SearchField /&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleResultSelectMock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;apiServiceMock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jest&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mockImplementation&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hello&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;adios&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;debug&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SearchField&lt;/span&gt;
      &lt;span class="na"&gt;handleResultSelect&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleResultSelectMock&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;apiService&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;apiServiceMock&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;textbox&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;apiServiceMock&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;not&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toHaveBeenCalled&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toHaveValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="nx"&gt;fireEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;change&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;search&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toHaveValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;search&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;advanceTimersByTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;apiServiceMock&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toHaveBeenCalledWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;search&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;apiServiceMock&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toHaveBeenCalledTimes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  What is happening in the example above?
&lt;/h4&gt;

&lt;p&gt;We imported all dependencies needed to test this component.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Jest DOM - to extend jest matchers&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;render&lt;/code&gt;, &lt;code&gt;cleanup&lt;/code&gt;, &lt;code&gt;fireEvent&lt;/code&gt; - React Testing Library utilities&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SearchField&lt;/code&gt; - the React component being tested
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@testing-library/jest-dom/extend-expect&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cleanup&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fireEvent&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@testing-library/react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;SearchField&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./SearchField&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We called Jest's function &lt;code&gt;afterEach&lt;/code&gt; and passed RTL's method &lt;code&gt;cleanup&lt;/code&gt; as an argument. &lt;code&gt;cleanup&lt;/code&gt; will make sure that there are no memory leaks between tests by unmounting everything mounted by RTL's &lt;code&gt;render&lt;/code&gt; method. We also called Jest's &lt;code&gt;useFakeTimers&lt;/code&gt; function to mock timer functions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;afterEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cleanup&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;useFakeTimers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The component requires two props which should be functions. Therefore, we started by mocking two functions that will be passed to the component as props - &lt;code&gt;handleResultSelectMock&lt;/code&gt; and &lt;code&gt;apiServiceMock&lt;/code&gt;. &lt;code&gt;handleResultSelectMock&lt;/code&gt; will be passed to &lt;code&gt;handleResultSelect&lt;/code&gt; and &lt;code&gt;apiServiceMock&lt;/code&gt; to &lt;code&gt;apiService&lt;/code&gt;. Then, RTL's &lt;code&gt;render&lt;/code&gt; method is called with the SearchField component as the argument.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;SearchField /&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleResultSelectMock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;apiServiceMock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jest&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mockImplementation&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hello&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;adios&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;debug&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SearchField&lt;/span&gt;
      &lt;span class="na"&gt;handleResultSelect&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleResultSelectMock&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;apiService&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;apiServiceMock&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  There will be times when the component being tested will require a &lt;code&gt;wrapper: Memory Router&lt;/code&gt; or a &lt;code&gt;context&lt;/code&gt; to render successfully. Take a look at the example below:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getByTestId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;UserContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Provider&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MainLoggedIn&lt;/span&gt;
      &lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;mockImplementation&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="na"&gt;globalMenu&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;requiredPermissions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Navbar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}]&lt;/span&gt;
        &lt;span class="p"&gt;}))&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;history&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;history&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;first_history&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;second_history&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;children&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;first_child&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;second_child&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;UserContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Provider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;,&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MemoryRouter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After &lt;code&gt;render&lt;/code&gt; is called, we should query the React DOM tree and find the elements we want to test. Below we used &lt;code&gt;getByRole&lt;/code&gt;, but RTL offers many other query selectors functions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;textbox&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To check values, start with the function &lt;code&gt;expect&lt;/code&gt; along one of the several matchers. Here we started by checking that the apiServiceMock has &lt;strong&gt;not&lt;/strong&gt; been called, then checks that the input field is an empty string (&lt;code&gt;value = ''&lt;/code&gt;) when the component first renders.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;apiServiceMock&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;not&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toHaveBeenCalled&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toHaveValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An event is fired using the function &lt;code&gt;change&lt;/code&gt; of RTL's &lt;code&gt;fireEvent&lt;/code&gt; to replicate the user's behaviour. This event will update the value of the input field from &lt;code&gt;''&lt;/code&gt; to &lt;code&gt;'search'&lt;/code&gt;. You can replicate other scenarios by using other &lt;code&gt;fireEvent&lt;/code&gt; methods such as &lt;code&gt;click()&lt;/code&gt;, &lt;code&gt;mouseOver()&lt;/code&gt;. Jest's &lt;code&gt;advanceTimersByTime&lt;/code&gt; method is called to move the mock timer forward by 600ms hence the number 600 is passed as an argument. &lt;code&gt;advanceTimersByTime&lt;/code&gt; makes sure that tasks that have been queued by a timer function and would be executed within the given time (600ms in this case) will be executed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;fireEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;change&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;search&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toHaveValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;search&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;advanceTimersByTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After firing the event, we expect a few things to happen, the &lt;code&gt;apiServiceMock&lt;/code&gt; function to be called once, and the argument passed to &lt;code&gt;apiServiceMock&lt;/code&gt; to match the current input's value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;apiServiceMock&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toHaveBeenCalledWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;search&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;apiServiceMock&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toHaveBeenCalledTimes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lastly, the &lt;code&gt;debug&lt;/code&gt; function is called to check what is rendered in the React tree and help debug the tests.&lt;/p&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Small and straightforward tests are better.&lt;/li&gt;
&lt;li&gt;Test each component independently.&lt;/li&gt;
&lt;li&gt;Focus on testing what the user will see and how they will interact with the component.&lt;/li&gt;
&lt;li&gt;Start building the tests &lt;em&gt;after&lt;/em&gt; assessing what needs to be tested.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  More on the topic:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/sapegin/jest-cheat-sheet" rel="noopener noreferrer"&gt;Jest cheat sheet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.sapegin.me/all/react-testing-3-jest-and-react-testing-library/" rel="noopener noreferrer"&gt;Modern React testing, part 3: Jest and React Testing Library&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.freecodecamp.org/news/the-right-way-to-test-react-components-548a4736ab22/" rel="noopener noreferrer"&gt;The Right Way to Test React Components&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://testing-library.com/docs/react-testing-library/intro/" rel="noopener noreferrer"&gt;React Testing Library - Introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://jestjs.io/docs/configuration" rel="noopener noreferrer"&gt;Configuring Jest&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pluralsight.com/guides/how-does-jest.fn()-work" rel="noopener noreferrer"&gt;Mock Functions or Spies Demystified - How Does &lt;code&gt;jest.fn()&lt;/code&gt; Work?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>react</category>
      <category>testing</category>
    </item>
    <item>
      <title>GraphQL microservices - Combining data from multiple microservices</title>
      <dc:creator>Jake Dowie</dc:creator>
      <pubDate>Thu, 17 Jun 2021 08:36:58 +0000</pubDate>
      <link>https://dev.to/jdlt/graphql-microservices-combining-data-from-multiple-microservices-8op</link>
      <guid>https://dev.to/jdlt/graphql-microservices-combining-data-from-multiple-microservices-8op</guid>
      <description>&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;Note: this post assumes a certain amount of familiarity with both microservice architectural style and GraphQL APIs. If you’re not familiar with either, check this in-depth tutorial on &lt;a href="https://www.howtographql.com/"&gt;GraphQL&lt;/a&gt; and/or this &lt;a href="https://www.nginx.com/blog/introduction-to-microservices/"&gt;primer on microservices&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Microservice-based application architectures have been increasing in popularity since their inception. Mostly because they’re widely held to solve several problems with monolithic application architectures: they’re more scalable, more reliable and easier to maintain.&lt;/p&gt;

&lt;p&gt;It’s a similar story for GraphQL as an API architecture: since it went open source in 2015 it’s become extremely popular in application development because it improves on REST in several key ways: it solves under- and over-fetching problems, makes your APIs self-documenting, and again is easier to maintain.&lt;/p&gt;

&lt;p&gt;At JDLT we’ve fully embraced both GraphQL and microservices for all these reasons and more, and as such we’ve learned a lot about how the two interact with each other, what challenges are posed by combining them, and how they bring out the best in each other. That’s what I’m going to talk about in this post.&lt;/p&gt;

&lt;h3&gt;
  
  
  The benefits and the conflict
&lt;/h3&gt;

&lt;p&gt;One of the benefits of GraphQL is that it allows you to serve your whole API from a single endpoint. Rather than dozens of endpoints, each doing something different and defined by a unique path, your client applications and users can hit a single endpoint with a query that defines exactly what they want from it. This means you don’t have to worry about different developers using different naming conventions for paths and you don’t have to worry about having to make multiple requests just to get one data set. It also significantly simplifies API management.&lt;/p&gt;

&lt;p&gt;Let’s say we have a social media app. Our app has a RESTful API with a &lt;code&gt;/users/&amp;lt;id&amp;gt;&lt;/code&gt; endpoint. You might hit it and get back a user object, complete with a name and the id of our chosen user’s best friend. If we want to show the logged-in user their best friend’ names in our UI, then one option is to make two requests to &lt;code&gt;/users/&amp;lt;id&amp;gt;&lt;/code&gt;; the first with the logged-in user’s id, and the second with her best friend’s id (which we only know from the response to the first call). This is slow (HTTP requests are probably the slowest part of your application) and it involves more code than we want to write. We want to write code to fetch some data we want, not code to fetch part of the data we want, and then once that’s come back to make another request which uses some of the first lots of data to fetch the rest.&lt;/p&gt;

&lt;p&gt;Our other option is to define our API endpoints based on the UI view which they’ll provide the data for, i.e. to build an endpoint that returns not only a user’s data but also some data about that user’s best friend. The problem here is that now our ability to change our UI is linked directly to our ability to change our API — even if we now just want to show our user’s best friend’s profile picture to this view, we have to update our API to return it from the relevant endpoint. This might not slow the application down, but it certainly slows development down.&lt;/p&gt;

&lt;p&gt;With GraphQL, our API knows how to retrieve a user for a given id, and it also knows that &lt;code&gt;user&lt;/code&gt;s have &lt;code&gt;name&lt;/code&gt;s and &lt;code&gt;bestFriend&lt;/code&gt;s. It even knows that &lt;code&gt;bestFriend&lt;/code&gt;s are in fact &lt;code&gt;user&lt;/code&gt;s and therefore it can retrieve a &lt;code&gt;name&lt;/code&gt; (or even a &lt;code&gt;bestFriend&lt;/code&gt;!) for the &lt;code&gt;bestFriend&lt;/code&gt; of a given user. When our UI changes, we update our query to ask for the relevant data, but the API remains unchanged.&lt;/p&gt;

&lt;p&gt;So, we’re sold on the benefits of a single API endpoint from which we can request whatever data we want. But, on the face of it, this seems to conflict with the fundamental concept of microservices: if they’re self-contained individual services, they define their own APIs; but if they all define their own APIs then we can’t access all of our data from a single endpoint.&lt;/p&gt;

&lt;p&gt;And we really do want our microservices to be self-contained. Perhaps checking the name of a user’s best friend is the most popular feature of our application. In that case, our &lt;code&gt;users&lt;/code&gt; service, which contains all the code to retrieve that information, will get used more than, for example, our email service, which might send notifications to our users when it’s their best friend’s birthday. So we probably want more instances of our &lt;code&gt;users&lt;/code&gt; service running than of our email service, so that nobody gets any dropped requests for their best friend’s name, and we’re not paying for unneeded availability for our email service. But if the two are part of the same monolithic application (allowing one API to access them both), this seems to be impossible.&lt;/p&gt;

&lt;h3&gt;
  
  
  The solution
&lt;/h3&gt;

&lt;p&gt;The solution to this problem is schema stitching, or, more specifically, GraphQL remote schema stitching. GraphQL schema stitching involves taking two separate GraphQL schemas (the data representation of a GraphQL API) and combining them into one. This is handy even in a monolithic application because it allows us to have two different services define their APIs in their respective directories, then stitch them together and expose them as a single API, essentially combining data from multiple microservices.&lt;/p&gt;

&lt;p&gt;GraphQL remote schema stitching is the same, except the schemas we’re stitching together aren’t just coming from different directories on the same server, they’re coming from different servers (in our case, different microservices).&lt;/p&gt;

&lt;p&gt;Once we know how to do that, we can create a new microservice that exists purely to stitch together the schemas from all our other microservices and expose them to create one GraphQL endpoint which can call any of our microservices. Essentially we'll be using a GraphQL microservice to allow combining data from multiple microservices.&lt;/p&gt;

&lt;p&gt;Now we have a single GraphQL endpoint for our whole application, and our microservices are still totally self-contained.&lt;/p&gt;

&lt;h3&gt;
  
  
  The implementation
&lt;/h3&gt;

&lt;p&gt;To implement this, we use a couple of npm packages from Apollo called &lt;a href="https://www.apollographql.com/docs/graphql-tools/"&gt;&lt;code&gt;graphql-tools&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://www.npmjs.com/package/apollo-link-http"&gt;&lt;code&gt;apollo-link-http&lt;/code&gt;&lt;/a&gt;. We'll also need &lt;a href="https://www.npmjs.com/package/node-fetch"&gt;&lt;code&gt;node-fetch&lt;/code&gt;&lt;/a&gt; for communicating between servers. To create our new GraphQL microservice, which we’ll call &lt;code&gt;graphql-server&lt;/code&gt;, we need to be able to do three things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;‘Introspect’ the schemas from our other microservices, which means to send them a GraphQL request which simply returns information about the schema&lt;/li&gt;
&lt;li&gt;Turn the responses from the introspection queries into a schema that graphql-server can execute by delegating incoming requests to the relevant microservice&lt;/li&gt;
&lt;li&gt;Merge all those new schemas together&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Fortunately, &lt;code&gt;graphql-tools&lt;/code&gt; has all the tools we need for each of these things!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;introspectSchema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;makeRemoteExecutableSchema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;mergeSchemas&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;graphql-tools&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;HttpLink&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;apollo-link-http&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;node-fetch&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 1
&lt;/h4&gt;

&lt;p&gt;First, we introspect our remote schema. This is simple: we just call &lt;code&gt;introspectSchema&lt;/code&gt;, passing in instructions about how to find the remote schema. And guess what, Apollo have a tool for creating those instructions too.&lt;/p&gt;

&lt;p&gt;Per the &lt;a href="https://www.apollographql.com/docs/link/#graphql-tools"&gt;&lt;code&gt;graphql-tools&lt;/code&gt; docs&lt;/a&gt;, "Apollo Links are chainable 'units' that you can snap together to define how each GraphQL request is handled by your GraphQL client."&lt;/p&gt;

&lt;p&gt;An &lt;code&gt;HttpLink&lt;/code&gt; is a specific type of Apollo Link which describes where to find a schema, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;schemaLink&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;HttpLink&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://your-api.com/graphql&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;schemaDefinition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;introspectSchema&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;schemaLink&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 2
&lt;/h4&gt;

&lt;p&gt;With step 1 complete, we already have everything we need for step 2, turning information about a remote schema into a schema that graphql-server can expose to client applications.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;remoteSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;makeRemoteExectuableSchema&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;schemaDefinition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;link&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;schemaLink&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 3
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;remoteSchema&lt;/code&gt; is now a fully-fledged GraphQL schema, ready to receive requests. We’ll need to repeat steps one and two for each remote schema (i.e. each of our microservices), and we’ll assume the resulting schemas are in an array called &lt;code&gt;remoteSchemas&lt;/code&gt;. All that remains is to merge them together.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mergedSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mergeSchemas&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;schemas&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;remoteSchemas&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;mergedSchema&lt;/code&gt; is a single schema that contains all the individual schemas from steps one and two, meaning it can execute any query or mutation that any of the remote schemas could execute. And it will do so by delegating the query or mutation to the microservice whose schema originally defined it.&lt;/p&gt;

&lt;p&gt;And that’s all there is to it! Just create a GraphQL server with &lt;code&gt;mergedSchema&lt;/code&gt; and expose it on an HTTP endpoint and you’re good to go.&lt;/p&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;We’ve covered a lot of ground here and achieved a lot of cool stuff, so let’s recap. We have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fetched data from each of our microservices about their GraphQL schemas and created links to them which will be used to delegate requests to them&lt;/li&gt;
&lt;li&gt;Turned all that data and those links into GraphQL schemas which are executable remotely&lt;/li&gt;
&lt;li&gt;Merged the new schemas together&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;…all of which allows us to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Expose a single GraphQL endpoint that provides access to the functionality of all our whole application&lt;/li&gt;
&lt;li&gt;Scale our microservices separately&lt;/li&gt;
&lt;li&gt;Develop any given microservice without affecting any other&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;…all at the same time!&lt;/p&gt;

&lt;p&gt;We’ve been using this sort of architecture in production for about 18 months now and we’re improving and refining it all the time. For our clients’ software and our internal applications, we’ve found that the GraphQL microservices architecture has helped us develop quick and reliable software quickly and reliably.&lt;/p&gt;

</description>
      <category>graphql</category>
      <category>microservices</category>
    </item>
  </channel>
</rss>
