title: React testing: "TypeError: MutationObserver is not a constructor"
body: <h2>The Problem</h2>
  <p>I'm trying to test a new release of an internal component library, which recently upgraded some dependencies and now uses <a href="https://en.wikipedia.org/wiki/Jest_(JavaScript_framework)" rel="nofollow noreferrer">Jest</a> 26 internally. That library also exports some testing helpers.</p>
  <p>In another codebase that utilizes the aforementioned component library, I'm getting the following when running certain unit tests:</p>
  <pre class="lang-none prettyprint-override"><code>TypeError: MutationObserver is not a constructor
  
      at /&lt;path_to_repo&gt;/node_modules/@testing-library/dom/dist/wait-for.js:78:18
  </code></pre>
  <p>This may or may not be related to the fact that the testing helpers exported by the component library relied on Jest 26. (It's hard to tell if these helpers are being used -- we've got some very big &quot;unit&quot; tests.)</p>
  <p>Relevant package versions (in the consuming codebase):</p>
  <ul>
  <li>react-scripts 3.4.4</li>
  <li>Jest 24.9.0</li>
  <li>testing-library/dom 7.26.3</li>
  <li>testing-library/jest-dom 5.10.0</li>
  <li>testing-library/react ^10.0.0</li>
  </ul>
  <p>Running <code>yarn list jsdom</code> yields the following:</p>
  <pre class="lang-none prettyprint-override"><code>├─ jest-environment-jsdom-fourteen@1.0.1
  │  └─ jsdom@14.1.0
  ├─ jest-environment-jsdom@24.9.0
  │  └─ jsdom@11.12.0
  └─ jsdom@16.4.0
  </code></pre>
  <p>I know that upgrading <code>react-scripts</code> and Jest would likely fix this issue, but I'm trying to find a way that doesn't involve that. (We ideally don't want this to be a prerequisite for upgrading to our new component library version.)</p>
  <h2>Attempted Solutions</h2>
  <h3>Forcing a Newer <code>jsdom</code></h3>
  <p>First I tried adding</p>
  <pre class="lang-json prettyprint-override"><code>&quot;resolutions&quot;: {
    &quot;jsdom&quot;: &quot;^14.0.0&quot;
  },
  </code></pre>
  <p>to my <code>package.json</code>. This did make <code>yarn list jsdom</code> output only <code>jsdom@14.1.0</code>, but I still got the same <code>TypeError</code>. Resolving to <code>^15.0.0</code> resulted in the same error, and resolving to <code>^16.0.0</code> gave me the following error:</p>
  <pre class="lang-none prettyprint-override"><code>TypeError: this.dom.runVMScript is not a function
  
    at JSDOMEnvironment.runScript (node_modules/jest-environment-jsdom/build/index.js:187:23)
  </code></pre>
  <h3>Using <code>jest-environment-jsdom-*</code></h3>
  <p>I tried following <a href="https://stackoverflow.com/a/61039444/500117">this thread</a> by installing <code>jest-environment-jsom-sixteen</code>. Altering my <code>test</code> script in <code>package.json</code> and running <code>yarn test --showConfig</code> yields a bunch of info including the following line:</p>
  <pre class="lang-json prettyprint-override"><code>&quot;testEnvironment&quot;: &quot;/&lt;path_to_repo&gt;/node_modules/jest-environment-jsdom-sixteen/lib/index.js&quot;,
  </code></pre>
  <p>If I add a <code>console.log(navigator.userAgent)</code> to my test, I also get</p>
  <pre class="lang-none prettyprint-override"><code>Mozilla/5.0 (darwin) AppleWebKit/537.36 (KHTML, like Gecko) jsdom/16.4.0
  </code></pre>
  <p>However, I still get the same <code>TypeError: MutationObserver is not a constructor</code>.</p>
  <p>I also tried <code>jest-environment-jsdom-fourteen</code> and <code>jest-environment-jsdom-fifteen</code>, and tried while forcing <code>jsdom</code> to <code>^14.0.0</code>. Same result.</p>
  <h3>Using <code>mutationobserver-shim</code></h3>
  <p>I ran <code>yarn add -D mutationobserver-shim</code> and imported it (with <code>import 'mutationobserver-shim'</code>) in my <code>jestSetup.ts</code> (which is what <code>globalSetup</code> in my Jest configuration points to), but that resulted in the following error:</p>
  <pre class="lang-none prettyprint-override"><code>ReferenceError: window is not defined
    at Object.&lt;anonymous&gt; (/&lt;path_to_repo&gt;/node_modules/mutationobserver-shim/dist/mutationobserver.min.js:12:1)
  </code></pre>
  <p>Adding the import instead to my test file yielded the same <code>TypeError</code> as above, and adding a <code>console.log(global.MutationObserver)</code> to my test file yielded <code>undefined</code>.</p>
  <h2>A Not-So-Great Solution</h2>
  <p>After a lot of trial and error, I discovered that if I 1) have <code>jest-environment-jsdom-sixteen</code> installed and tell Jest to use it and 2) add <code>import 'mutationobserver-shim'</code> <em>in my test file</em>, and the tests will pass. However, if I put add the import to my Jest <code>globalSetup</code> file, it doesn't work. I get the same <code>ReferenceError: window is not defined</code> error as before.</p>
  <h2>My Question</h2>
  <p>How can I get rid of both errors without requiring users of our component library to add an import statement to all of their test files?</p>