title: React test not working with current Jest config, Gatsby and gatsby-theme-i18n
body: <p>I am fairly new to testing with Gatsby and Jest and I am encountering issues with my current setup.</p>
  <p>I am trying to build a site with Gatsby and I would like for CI purposes to run unit tests with Jest and react-testing-library.</p>
  <p>I initially was able to run a simple test:</p>
  <pre><code>describe('&lt;Header&gt;', () =&gt; {
    describe('mounts', () =&gt; {
      test('component mounts', () =&gt; {
        const { container } = render(
          &lt;Header /&gt;
        );
        expect(container).toBeInTheDocument();
      });
    });
  
   describe('click', () =&gt; {
      const { container } = render(&lt;Header /&gt;);
      expect(screen.getByText('Light mode ☀')).toBeInTheDocument();
      fireEvent(
        getByText(container, 'Light mode ☀'),
        new MouseEvent('click', {
          bubbles: true,
          cancelable: true,
        }),
      );
      expect(screen.getByText('Dark mode ☾')).toBeInTheDocument();
    });
  </code></pre>
  <p>where my render is a customized one:</p>
  <pre><code>const AllTheProviders = ({ children }) =&gt; {
    const [dark, setDark] = useState(true);
    return (
      &lt;ThemeContext.Provider
        value={{
          dark,
          toggleDark: () =&gt; setDark(!dark),
        }}
      &gt;
        {children}
      &lt;/ThemeContext.Provider&gt;
    );
  };
  
  const customRender = (ui, options) =&gt;
    render(ui, { wrapper: AllTheProviders, ...options });
  
  // re-export everything
  export * from '@testing-library/react';
  
  // override render method
  export { customRender as render };
  </code></pre>
  <p>and the Header a simple component that consumes the context and toggles the theme from dark to light.</p>
  <p>I since then added <code>gatsby-theme-i18n</code> to handle i18n and tweaked my jest config to add:</p>
  <p><code>transformIgnorePatterns: ['node_modules/(?!(gatsby-theme-i18n)/)']</code></p>
  <p>The Header is now wrapped in a <code>Layout</code> component that provides the locale and location (with the Help for <code>Location</code> and <code>@reach/router</code> that comes with Gatsby) so I can have a language toggle in the header</p>
  <p>In the Layout:</p>
  <pre><code>import { Location } from '@reach/router';
  [...]
   &lt;Location&gt;
    {(location) =&gt; (
      &lt;Header
        siteTitle={data.site.siteMetadata.title}
        location={location}
        locale={locale}
      /&gt;
     )}
  &lt;/Location&gt;
  </code></pre>
  <p>The Header makes use of <code>LocalizedLink</code> from gatsby-theme-i18n` to prefix the right locale</p>
  <pre><code>  &lt;li key={langKey}&gt;
      &lt;LocalizedLink key={langKey} to={to} language={langKey}&gt;
        {langKey}
      &lt;/LocalizedLink&gt;
    &lt;/li&gt;
  </code></pre>
  <p>I also changed the test to:</p>
  <pre><code>describe('mounts', () =&gt; {
      test('component mounts', () =&gt; {
        const { container } = render(
          &lt;Location&gt;
            {(location) =&gt; (
              &lt;Header siteTitle=&quot;site title&quot; location={location} locale=&quot;en&quot; /&gt;
            )}
          &lt;/Location&gt;,
        );
        expect(container).toBeInTheDocument();
      });
    });
  </code></pre>
  <p>However, I get an error when trying to run the test:</p>
  <pre><code>    TypeError: Cannot read property 'themeI18N' of undefined
  
        21 |
        22 | const customRender = (ui, options) =&gt;
      &gt; 23 |   render(ui, { wrapper: AllTheProviders, ...options });
           |   ^
  </code></pre>
  <p>specifically coming from at <code>useLocalization (node_modules/gatsby-theme-i18n/src/hooks/use-localization.js:9:7)</code></p>
  <p>where the Gatsby theme provides the i18n info through a graphQL query:</p>
  <pre><code> const {
      themeI18N: { defaultLang, config },
    } = useStaticQuery(graphql`
      {
        themeI18N {
          defaultLang
          config {
            code
            hrefLang
            dateFormat
            langDir
            localName
            name
          }
        }
      }
    `)
  </code></pre>
  <p>I understand that Jest does not 'understand' what to do with the i18n passed through the <code>gatsby-theme-i18n</code> via the Layout and if I switch my <code>LocalizedLink</code> to a normal Gatsby <code>Link</code>, the test passes (and I can console.log the container to see it's indeed a React element with the right info).</p>
  <p>I tried a few things I saw online like using <code>const { useLocalization } = require('gatsby-theme-i18n');</code> but to no avail.</p>
  <p>Any idea how to handle this?
  Should I mock the utils from <code>gatsby-theme-i18n</code> like other elements from Gatsby are mocked (Link etc.) <a href="https://www.gatsbyjs.org/docs/unit-testing/#3-useful-mocks-to-complete-your-testing-environment" rel="nofollow noreferrer">following the docs</a>?</p>
  <h3>EDIT</h3>
  <p>Thanks to the author of the library, LekoArts, and a friend a mine, I managed to make it work :)
  If somebody has the same issue, you need to mock the response from the useStaticQuery of the useLocalization hook.</p>
  <p>I have a mock file that does it:</p>
  <pre><code>// Libs
  const React = require('react');
  
  const gatsby = jest.requireActual('gatsby');
  
  // Utils
  const siteMetaData = require('../src/utils/siteMetaData');
  
  module.exports = {
    ...gatsby,
    graphql: jest.fn(),
    Link: jest.fn().mockImplementation(
      // these props are invalid for an `a` tag
      ({
        activeClassName,
        activeStyle,
        getProps,
        innerRef,
        partiallyActive,
        ref,
        replace,
        to,
        ...rest
      }) =&gt;
        React.createElement('a', {
          ...rest,
          href: to,
        }),
    ),
    StaticQuery: jest.fn(),
    useStaticQuery: jest.fn().mockImplementation(() =&gt; ({
      site: {
        siteMetadata: {
          ...siteMetaData,
        },
      },
      themeI18N: {
        defaultLang: 'en',
        config: {
          code: 'en',
          hrefLang: 'en-CA',
          name: 'English',
          localName: 'English',
          langDir: 'ltr',
          dateFormat: 'MM/DD/YYYY',
        },
      },
    })),
  };
  </code></pre>
  <p>and my test:</p>
  <pre><code>// Libs
  import React from 'react';
  
  // Utils
  import { Location } from '@reach/router';
  import { render, fireEvent, getByText, screen } from './utils/test-utils';
  
  // Component
  import Header from '../header';
  
  describe('&lt;Header&gt;', () =&gt; {
    describe('mounts', () =&gt; {
      test('component mounts', () =&gt; {
        const { container } = render(
          &lt;Location&gt;
            {(location) =&gt; (
              &lt;Header siteTitle=&quot;site title&quot; location={location} locale=&quot;en&quot; /&gt;
            )}
          &lt;/Location&gt;,
        );
        expect(container).toBeInTheDocument();
      });
    });
  
    describe('click', () =&gt; {
      test('toggle language', () =&gt; {
        const { container } = render(
          &lt;Location&gt;
            {(location) =&gt; (
              &lt;Header siteTitle=&quot;site title&quot; location={location} locale=&quot;en&quot; /&gt;
            )}
          &lt;/Location&gt;,
        );
        expect(screen.getByText('Light mode ☀')).toBeInTheDocument();
        fireEvent(
          getByText(container, 'Light mode ☀'),
          new MouseEvent('click', {
            bubbles: true,
            cancelable: true,
          }),
        );
        expect(screen.getByText('Dark mode ☾')).toBeInTheDocument();
      });
    });
  });
  </code></pre>
  <p>You can find <a href="https://github.com/gatsbyjs/themes/issues/43#issuecomment-666982539" rel="nofollow noreferrer">more information here</a></p>