title: How can I properly test my React Native OAuth wrapper component?
body: <p>I have written a React Native "Auth Portal" component, that links with an existing OAuth portal and handles getting the auth-code from the redirect URI and the subsequent token exchange request. It seems to be working well, but clearly I need to test this assumption, so I am trying <strong>to write unit/functional tests</strong>. How can I properly do this?</p>
  
  <p>I originally considered extracting the functions used in the two <code>useEffect</code>s out into separate, isolated functions and taking, for example, the <code>authCode</code> as an argument instead of from state and mocking this input.</p>
  
  <p>However, I believe a better strategy is to test the component as a whole and just mock the response to the axios post request, comparing that mock to what get's stored in the AsyncStorage, as well as mocking a bad request/response to test the error handling.</p>
  
  <p><strong>Is this a good approach?</strong></p>
  
  <pre><code>import axios from 'axios'
  import AsyncStorage from '@react-native-community/async-storage'
  import React, { useEffect, useState } from 'react'
  import { Linking } from 'react-native'
  import InAppBrowser from 'react-native-inappbrowser-reborn'
  import { LoadingIndicator } from '../LoadingIndicator'
  
  interface AuthPortalProps {
      client_id: string
      scopes: string[]
      client_secret: string
      redirect_uri: string
      onAuthComplete: () =&gt; void
      onError: () =&gt; void
  }
  
  interface ApiDataResponse {
      token_type: string
      expires_in: number
      access_token: string
      refresh_token: string
  }
  
  export const AuthPortal = ({
      client_id,
      scopes,
      client_secret,
      redirect_uri,
      onAuthComplete,
      onError,
  }: AuthPortalProps) =&gt; {
      const [authCode, setAuthCode] = useState()
  
      const getAuthCodeFromRedirectUri = async (url: string) =&gt; {
          if (url.includes('code=')) {
              const regex = /[^=]+$/g
              const code = url.match(regex)!.toString()
  
              await setAuthCode(code)
          }
      }
  
      useEffect(() =&gt; {
          const getAuthCode = async () =&gt; {
              const url = `https://example.com/auth/?response_type=code&amp;client_id=${client_id}&amp;redirect_uri=${redirect_uri}&amp;scope=${scopes}`
  
              if (!authCode) {
                  try {
                      InAppBrowser.openAuth(url, redirect_uri).then(response =&gt; {
                          if (response.type === 'success' &amp;&amp; response.url &amp;&amp; response.url.includes('code=')) {
                              getAuthCodeFromRedirectUri(response.url)
                              Linking.openURL(redirect_uri)
                          }
                      })
                  } catch (error) {
                      console.log('Error: ', error.message)
                      onError()
                  }
              }
          }
  
          getAuthCode()
          return () =&gt; {
              InAppBrowser.closeAuth()
          }
      }, [authCode, client_id, onError, redirect_uri, scopes])
  
      useEffect(() =&gt; {
          const getAuthRefreshToken = async () =&gt; {
              if (authCode) {
                  try {
                      const { data }: { data: ApiDataResponse } = await axios.post(
                          'https://example.com/auth',
                          {
                              grant_type: 'authorization_code',
                              client_id: `${client_id}`,
                              code: `${authCode}`,
                              client_secret: `${client_secret}`,
                              redirect_uri: `${redirect_uri}`,
                          }
                      )
  
                      await Promise.all([
                          AsyncStorage.setItem('access_token', data.access_token),
                          AsyncStorage.setItem('refresh_token', data.refresh_token),
                      ])
                      setTimeout(() =&gt; {
                          onAuthComplete()
                      }, 1000)
                  } catch (error) {
                      if (error.response) {
                          console.log('Error: ', error.response)
                      } else if (error.request) {
                          console.log('Error: ', error.request)
                      } else {
                          console.log('Error: ', error.message)
                      }
                      onError()
                  }
              }
          }
  
          getAuthRefreshToken()
      }, [authCode, client_id, client_secret, onAuthComplete, onError, redirect_uri])
  
      return &lt;LoadingIndicator /&gt;
  }
  </code></pre>