Repository: styleguidist/react-styleguidist
Pull request #2086 (2022-12-13 08:19:24)

Replace enzyme with React testing library
Replace Enzyme with React Testing library.  Enzyme does not support React 18


codecov[bot]: # [Codecov](https://codecov.io/gh/styleguidist/react-styleguidist/pull/2086?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=styleguidist) Report
> Merging [#2086](https://codecov.io/gh/styleguidist/react-styleguidist/pull/2086?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=styleguidist) (212cf66) into [master](https://codecov.io/gh/styleguidist/react-styleguidist/commit/5e6f5cf506b34739e5aaf8a1ddcb966a4077c9f5?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=styleguidist) (5e6f5cf) will **decrease** coverage by `0.04%`.
> The diff coverage is `95.45%`.

<details><summary>Additional details and impacted files</summary>


| [Impacted Files](https://codecov.io/gh/styleguidist/react-styleguidist/pull/2086?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=styleguidist) | Coverage Δ | |
|---|---|---|
| [test/deabsdeepSerializer.js](https://codecov.io/gh/styleguidist/react-styleguidist/pull/2086/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=styleguidist#diff-dGVzdC9kZWFic2RlZXBTZXJpYWxpemVyLmpz) | `95.45% <95.45%> (ø)` | |

</details>

Patch:
diff --git a/docs/Development.md b/docs/Development.md
index 19884430..f9c8b2be 100644
--- a/docs/Development.md
+++ b/docs/Development.md
@@ -101,7 +101,7 @@ Because of isolation and theming you need to explicitly declare `fontFamily`, `f
 
 ## Testing
 
-We’re using [Jest with Enzyme](http://blog.sapegin.me/all/react-jest) for testing. Put your component tests into `Component.spec.js` file in the same folder and all other tests into `__tests__/filename.spec.js`.
+We’re using [Jest with React Test Renderer](https://reactjs.org/docs/test-renderer.html) for testing. Put your component tests into `Component.spec.js` file in the same folder and all other tests into `__tests__/filename.spec.js`.
 
 To test particular class names use `classes` function (available in the global namespace in tests):
 
@@ -113,11 +113,12 @@ const props = {
 }
 
 it('should render active styles', () => {
-  const actual = shallow(
+  const renderer = createRenderer()
+  renderer.render(
     <TabButtonRenderer {...props} active>
       pizza
     </TabButtonRenderer>
   )
-  expect(actual).toMatchSnapshot()
+  expect(actual.toJson()).toMatchSnapshot()
 })
 ```
diff --git a/package-lock.json b/package-lock.json
index 6289043a..2847a9f6 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -10,6 +10,7 @@
       "license": "MIT",
       "dependencies": {
         "@tippyjs/react": "4.1.0",
+        "@types/react-test-renderer": "^17.0.0",
         "@vxna/mini-html-webpack-template": "^2.0.0",
         "acorn": "^6.4.1",
         "acorn-jsx": "^5.1.0",
@@ -25,6 +26,7 @@
         "doctrine": "^3.0.0",
         "es6-object-assign": "~1.1.0",
         "es6-promise": "^4.2.8",
+        "escape-string-regexp": "^1.0.5",
         "escodegen": "^1.12.0",
         "estree-walker": "~0.9.0",
         "fastest-levenshtein": "^1.0.9",
@@ -34,6 +36,7 @@
         "glob": "^7.1.5",
         "glogg": "^1.0.2",
         "hash-sum": "^2.0.0",
+        "is-plain-obj": "^1.1.0",
         "javascript-stringify": "^2.0.0",
         "jss": "^10.9.0",
         "jss-plugin-camel-case": "^10.9.0",
@@ -87,7 +90,6 @@
         "@types/buble": "^0.19.2",
         "@types/copy-webpack-plugin": "^5.0.2",
         "@types/doctrine": "0.0.3",
-        "@types/enzyme": "^3.10.3",
         "@types/escodegen": "0.0.6",
         "@types/estree": "^0.0.39",
         "@types/hash-sum": "^1.0.0",
@@ -106,19 +108,15 @@
         "@types/webpack-env": "^1.14.1",
         "@typescript-eslint/eslint-plugin": "^4.4.1",
         "@typescript-eslint/parser": "^4.4.1",
-        "@wojtekmaj/enzyme-adapter-react-17": "^0.6.7",
         "babel-core": "^7.0.0-bridge.0",
         "babel-eslint": "^10.1.0",
         "babel-jest": "^26.6.0",
         "babel-loader": "^8.1.0",
-        "cheerio": "^1.0.0-rc.3",
         "css-loader": "^6.7.1",
         "danger": "^10.5.3",
         "deabsdeep": "^1.0.6",
         "deepfreeze": "^2.0.0",
         "dog-names": "^2.0.0",
-        "enzyme": "^3.10.0",
-        "enzyme-to-json": "^3.4.3",
         "eslint": "^7.11.0",
         "eslint-config-tamia": "^7.2.6",
         "eslint-import-resolver-typescript": "^2.3.0",
@@ -130,7 +128,6 @@
         "fs-extra": "^9.0.0",
         "husky": "^4.3.0",
         "jest": "^26.6.0",
-        "jest-serializer-html": "^7.0.0",
         "keymirror": "^0.1.1",
         "lint-staged": "^10.5.1",
         "memfs": "~2.15.5",
@@ -5203,15 +5200,6 @@
         "magic-string": "^0.25.0"
       }
     },
-    "node_modules/@types/cheerio": {
-      "version": "0.22.13",
-      "resolved": "https://registry.npmjs.org/@types/cheerio/-/cheerio-0.22.13.tgz",
-      "integrity": "sha512-OZd7dCUOUkiTorf97vJKwZnSja/DmHfuBAroe1kREZZTCf/tlFecwHhsOos3uVHxeKGZDwzolIrCUApClkdLuA==",
-      "dev": true,
-      "dependencies": {
-        "@types/node": "*"
-      }
-    },
     "node_modules/@types/connect": {
       "version": "3.4.33",
       "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.33.tgz",
@@ -5246,16 +5234,6 @@
       "integrity": "sha1-6JLSk8ksnB0/mvcsFaVU+8fgiVo=",
       "dev": true
     },
-    "node_modules/@types/enzyme": {
-      "version": "3.10.3",
-      "resolved": "https://registry.npmjs.org/@types/enzyme/-/enzyme-3.10.3.tgz",
-      "integrity": "sha512-f/Kcb84sZOSZiBPCkr4He9/cpuSLcKRyQaEE20Q30Prx0Dn6wcyMAWI0yofL6yvd9Ht9G7EVkQeRqK0n5w8ILw==",
-      "dev": true,
-      "dependencies": {
-        "@types/cheerio": "*",
-        "@types/react": "*"
-      }
-    },
     "node_modules/@types/escodegen": {
       "version": "0.0.6",
       "resolved": "https://registry.npmjs.org/@types/escodegen/-/escodegen-0.0.6.tgz",
@@ -5471,8 +5449,7 @@
     "node_modules/@types/prop-types": {
       "version": "15.7.3",
       "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz",
-      "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==",
-      "dev": true
+      "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw=="
     },
     "node_modules/@types/qs": {
       "version": "6.9.5",
@@ -5503,11 +5480,39 @@
         "@types/react": "*"
       }
     },
+    "node_modules/@types/react-test-renderer": {
+      "version": "17.0.2",
+      "resolved": "https://registry.npmjs.org/@types/react-test-renderer/-/react-test-renderer-17.0.2.tgz",
+      "integrity": "sha512-+F1KONQTBHDBBhbHuT2GNydeMpPuviduXIVJRB7Y4nma4NR5DrTJfMMZ+jbhEHbpwL+Uqhs1WXh4KHiyrtYTPg==",
+      "dependencies": {
+        "@types/react": "^17"
+      }
+    },
+    "node_modules/@types/react-test-renderer/node_modules/@types/react": {
+      "version": "17.0.50",
+      "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.50.tgz",
+      "integrity": "sha512-ZCBHzpDb5skMnc1zFXAXnL3l1FAdi+xZvwxK+PkglMmBrwjpp9nKaWuEvrGnSifCJmBFGxZOOFuwC6KH/s0NuA==",
+      "dependencies": {
+        "@types/prop-types": "*",
+        "@types/scheduler": "*",
+        "csstype": "^3.0.2"
+      }
+    },
+    "node_modules/@types/react-test-renderer/node_modules/csstype": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz",
+      "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw=="
+    },
     "node_modules/@types/retry": {
       "version": "0.12.1",
       "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.1.tgz",
       "integrity": "sha512-xoDlM2S4ortawSWORYqsdU+2rxdh4LRW9ytc3zmT37RIKQh6IHyKwwtKhKis9ah8ol07DCkZxPt8BBvPjC6v4g=="
     },
+    "node_modules/@types/scheduler": {
+      "version": "0.16.2",
+      "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz",
+      "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew=="
+    },
     "node_modules/@types/serve-index": {
       "version": "1.9.1",
       "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz",
@@ -6162,46 +6167,6 @@
         }
       }
     },
-    "node_modules/@wojtekmaj/enzyme-adapter-react-17": {
-      "version": "0.6.7",
-      "resolved": "https://registry.npmjs.org/@wojtekmaj/enzyme-adapter-react-17/-/enzyme-adapter-react-17-0.6.7.tgz",
-      "integrity": "sha512-B+byiwi/T1bx5hcj9wc0fUL5Hlb5giSXJzcnEfJVl2j6dGV2NJfcxDBYX0WWwIxlzNiFz8kAvlkFWI2y/nscZQ==",
-      "dev": true,
-      "dependencies": {
-        "@wojtekmaj/enzyme-adapter-utils": "^0.1.4",
-        "enzyme-shallow-equal": "^1.0.0",
-        "has": "^1.0.0",
-        "prop-types": "^15.7.0",
-        "react-is": "^17.0.0",
-        "react-test-renderer": "^17.0.0"
-      },
-      "peerDependencies": {
-        "enzyme": "^3.0.0",
-        "react": "^17.0.0-0",
-        "react-dom": "^17.0.0-0"
-      }
-    },
-    "node_modules/@wojtekmaj/enzyme-adapter-react-17/node_modules/react-is": {
-      "version": "17.0.2",
-      "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
-      "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
-      "dev": true
-    },
-    "node_modules/@wojtekmaj/enzyme-adapter-utils": {
-      "version": "0.1.4",
-      "resolved": "https://registry.npmjs.org/@wojtekmaj/enzyme-adapter-utils/-/enzyme-adapter-utils-0.1.4.tgz",
-      "integrity": "sha512-ARGIQSIIv3oBia1m5Ihn1VU0FGmft6KPe39SBKTb8p7LSXO23YI4kNtc4M/cKoIY7P+IYdrZcgMObvedyjoSQA==",
-      "dev": true,
-      "dependencies": {
-        "function.prototype.name": "^1.1.0",
-        "has": "^1.0.0",
-        "object.fromentries": "^2.0.0",
-        "prop-types": "^15.7.0"
-      },
-      "peerDependencies": {
-        "react": "^17.0.0-0"
-      }
-    },
     "node_modules/@xtuc/ieee754": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
@@ -6535,12 +6500,6 @@
         "node": ">=0.10.0"
       }
     },
-    "node_modules/array-filter": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-1.0.0.tgz",
-      "integrity": "sha1-uveeYubvTCpMC4MSMtr/7CUfnYM=",
-      "dev": true
-    },
     "node_modules/array-find-index": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz",
@@ -6600,20 +6559,6 @@
         "node": ">=0.10.0"
       }
     },
-    "node_modules/array.prototype.flat": {
-      "version": "1.2.2",
-      "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.2.tgz",
-      "integrity": "sha512-VXjh7lAL4KXKF2hY4FnEW9eRW6IhdvFW1sN/JwLbmECbCgACCnBHNyP3lFiYuttr0jxRN9Bsc5+G27dMseSWqQ==",
-      "dev": true,
-      "dependencies": {
-        "define-properties": "^1.1.3",
-        "es-abstract": "^1.15.0",
-        "function-bind": "^1.1.1"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      }
-    },
     "node_modules/array.prototype.flatmap": {
       "version": "1.2.3",
       "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.3.tgz",
@@ -7247,12 +7192,6 @@
         "multicast-dns": "^7.2.4"
       }
     },
-    "node_modules/boolbase": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
-      "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=",
-      "dev": true
-    },
     "node_modules/brace-expansion": {
       "version": "1.1.11",
       "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@@ -7544,23 +7483,6 @@
         "url": "https://github.com/sponsors/wooorm"
       }
     },
-    "node_modules/cheerio": {
-      "version": "1.0.0-rc.3",
-      "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.3.tgz",
-      "integrity": "sha512-0td5ijfUPuubwLUu0OBoe98gZj8C/AA+RW3v67GPlGOrvxWjZmBXiBCRU+I8VEiNyJzjth40POfHiz2RB3gImA==",
-      "dev": true,
-      "dependencies": {
-        "css-select": "~1.2.0",
-        "dom-serializer": "~0.1.1",
-        "entities": "~1.1.1",
-        "htmlparser2": "^3.9.1",
-        "lodash": "^4.15.0",
-        "parse5": "^3.0.1"
-      },
-      "engines": {
-        "node": ">= 0.6"
-      }
-    },
     "node_modules/chokidar": {
       "version": "2.1.8",
       "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz",
@@ -8426,27 +8348,6 @@
         "node": ">=10"
       }
     },
-    "node_modules/css-select": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz",
-      "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=",
-      "dev": true,
-      "dependencies": {
-        "boolbase": "~1.0.0",
-        "css-what": "2.1",
-        "domutils": "1.5.1",
-        "nth-check": "~1.0.1"
-      }
-    },
-    "node_modules/css-what": {
-      "version": "2.1.3",
-      "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz",
-      "integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==",
-      "dev": true,
-      "engines": {
-        "node": "*"
-      }
-    },
     "node_modules/css.escape": {
       "version": "1.5.1",
       "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz",
@@ -9122,15 +9023,6 @@
         "node": ">= 8.3"
       }
     },
-    "node_modules/diffable-html": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/diffable-html/-/diffable-html-4.0.0.tgz",
-      "integrity": "sha512-keJdgy2qBkdrrnwP1YE6e834d4Y+mV0aRFzk8w7WzyAJVbQVfcJltSmUWB3r/NOoO/0jt7RdJlvy5ioyqvmQcw==",
-      "dev": true,
-      "dependencies": {
-        "htmlparser2": "^3.9.2"
-      }
-    },
     "node_modules/dir-glob": {
       "version": "3.0.1",
       "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
@@ -9150,12 +9042,6 @@
         "node": ">=8"
       }
     },
-    "node_modules/discontinuous-range": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/discontinuous-range/-/discontinuous-range-1.0.0.tgz",
-      "integrity": "sha1-44Mx8IRLukm5qctxx3FYWqsbxlo=",
-      "dev": true
-    },
     "node_modules/dns-equal": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz",
@@ -9205,22 +9091,6 @@
       "integrity": "sha512-TvrjBckDy2c6v6RLxPv5QXOnU+SmF9nBII5621Ve5fu6Z/BDrENurBEvlC1f44lKEUVqOpK4w9E5Idc5/EgkLQ==",
       "dev": true
     },
-    "node_modules/dom-serializer": {
-      "version": "0.1.1",
-      "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz",
-      "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==",
-      "dev": true,
-      "dependencies": {
-        "domelementtype": "^1.3.0",
-        "entities": "^1.1.1"
-      }
-    },
-    "node_modules/domelementtype": {
-      "version": "1.3.1",
-      "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz",
-      "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==",
-      "dev": true
-    },
     "node_modules/domexception": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz",
@@ -9242,25 +9112,6 @@
         "node": ">=8"
       }
     },
-    "node_modules/domhandler": {
-      "version": "2.4.2",
-      "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz",
-      "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==",
-      "dev": true,
-      "dependencies": {
-        "domelementtype": "1"
-      }
-    },
-    "node_modules/domutils": {
-      "version": "1.5.1",
-      "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz",
-      "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=",
-      "dev": true,
-      "dependencies": {
-        "dom-serializer": "0",
-        "domelementtype": "1"
-      }
-    },
     "node_modules/duplexer": {
       "version": "0.1.2",
       "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz",
@@ -9379,12 +9230,6 @@
         "node": ">=6"
       }
     },
-    "node_modules/entities": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz",
-      "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==",
-      "dev": true
-    },
     "node_modules/envinfo": {
       "version": "7.8.1",
       "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz",
@@ -9397,63 +9242,6 @@
         "node": ">=4"
       }
     },
-    "node_modules/enzyme": {
-      "version": "3.10.0",
-      "resolved": "https://registry.npmjs.org/enzyme/-/enzyme-3.10.0.tgz",
-      "integrity": "sha512-p2yy9Y7t/PFbPoTvrWde7JIYB2ZyGC+NgTNbVEGvZ5/EyoYSr9aG/2rSbVvyNvMHEhw9/dmGUJHWtfQIEiX9pg==",
-      "dev": true,
-      "dependencies": {
-        "array.prototype.flat": "^1.2.1",
-        "cheerio": "^1.0.0-rc.2",
-        "function.prototype.name": "^1.1.0",
-        "has": "^1.0.3",
-        "html-element-map": "^1.0.0",
-        "is-boolean-object": "^1.0.0",
-        "is-callable": "^1.1.4",
-        "is-number-object": "^1.0.3",
-        "is-regex": "^1.0.4",
-        "is-string": "^1.0.4",
-        "is-subset": "^0.1.1",
-        "lodash.escape": "^4.0.1",
-        "lodash.isequal": "^4.5.0",
-        "object-inspect": "^1.6.0",
-        "object-is": "^1.0.1",
-        "object.assign": "^4.1.0",
-        "object.entries": "^1.0.4",
-        "object.values": "^1.0.4",
-        "raf": "^3.4.0",
-        "rst-selector-parser": "^2.2.3",
-        "string.prototype.trim": "^1.1.2"
-      }
-    },
-    "node_modules/enzyme-shallow-equal": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/enzyme-shallow-equal/-/enzyme-shallow-equal-1.0.4.tgz",
-      "integrity": "sha512-MttIwB8kKxypwHvRynuC3ahyNc+cFbR8mjVIltnmzQ0uKGqmsfO4bfBuLxb0beLNPhjblUEYvEbsg+VSygvF1Q==",
-      "dev": true,
-      "dependencies": {
-        "has": "^1.0.3",
-        "object-is": "^1.1.2"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/enzyme-to-json": {
-      "version": "3.4.3",
-      "resolved": "https://registry.npmjs.org/enzyme-to-json/-/enzyme-to-json-3.4.3.tgz",
-      "integrity": "sha512-jqNEZlHqLdz7OTpXSzzghArSS3vigj67IU/fWkPyl1c0TCj9P5s6Ze0kRkYZWNEoCqCR79xlQbigYlMx5erh8A==",
-      "dev": true,
-      "dependencies": {
-        "lodash": "^4.17.15"
-      },
-      "engines": {
-        "node": ">=4.0.0"
-      },
-      "peerDependencies": {
-        "enzyme": "^3.4.0"
-      }
-    },
     "node_modules/error-ex": {
       "version": "1.3.2",
       "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
@@ -9557,7 +9345,7 @@
     "node_modules/escape-string-regexp": {
       "version": "1.0.5",
       "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
-      "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
+      "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
       "engines": {
         "node": ">=0.8.0"
       }
@@ -11848,12 +11636,14 @@
     },
     "node_modules/fsevents/node_modules/abbrev": {
       "version": "1.1.1",
+      "dev": true,
       "inBundle": true,
       "license": "ISC",
       "optional": true
     },
     "node_modules/fsevents/node_modules/ansi-regex": {
       "version": "2.1.1",
+      "dev": true,
       "inBundle": true,
       "license": "MIT",
       "optional": true,
@@ -11863,12 +11653,14 @@
     },
     "node_modules/fsevents/node_modules/aproba": {
       "version": "1.2.0",
+      "dev": true,
       "inBundle": true,
       "license": "ISC",
       "optional": true
     },
     "node_modules/fsevents/node_modules/are-we-there-yet": {
       "version": "1.1.5",
+      "dev": true,
       "inBundle": true,
       "license": "ISC",
       "optional": true,
@@ -11879,12 +11671,14 @@
     },
     "node_modules/fsevents/node_modules/balanced-match": {
       "version": "1.0.0",
+      "dev": true,
       "inBundle": true,
       "license": "MIT",
       "optional": true
     },
     "node_modules/fsevents/node_modules/brace-expansion": {
       "version": "1.1.11",
+      "dev": true,
       "inBundle": true,
       "license": "MIT",
       "optional": true,
@@ -11895,12 +11689,14 @@
     },
     "node_modules/fsevents/node_modules/chownr": {
       "version": "1.1.1",
+      "dev": true,
       "inBundle": true,
       "license": "ISC",
       "optional": true
     },
     "node_modules/fsevents/node_modules/code-point-at": {
       "version": "1.1.0",
+      "dev": true,
       "inBundle": true,
       "license": "MIT",
       "optional": true,
@@ -11910,24 +11706,28 @@
     },
     "node_modules/fsevents/node_modules/concat-map": {
       "version": "0.0.1",
+      "dev": true,
       "inBundle": true,
       "license": "MIT",
       "optional": true
     },
     "node_modules/fsevents/node_modules/console-control-strings": {
       "version": "1.1.0",
+      "dev": true,
       "inBundle": true,
       "license": "ISC",
       "optional": true
     },
     "node_modules/fsevents/node_modules/core-util-is": {
       "version": "1.0.2",
+      "dev": true,
       "inBundle": true,
       "license": "MIT",
       "optional": true
     },
     "node_modules/fsevents/node_modules/debug": {
       "version": "4.1.1",
+      "dev": true,
       "inBundle": true,
       "license": "MIT",
       "optional": true,
@@ -11937,6 +11737,7 @@
     },
     "node_modules/fsevents/node_modules/deep-extend": {
       "version": "0.6.0",
+      "dev": true,
       "inBundle": true,
       "license": "MIT",
       "optional": true,
@@ -11946,12 +11747,14 @@
     },
     "node_modules/fsevents/node_modules/delegates": {
       "version": "1.0.0",
+      "dev": true,
       "inBundle": true,
       "license": "MIT",
       "optional": true
     },
     "node_modules/fsevents/node_modules/detect-libc": {
       "version": "1.0.3",
+      "dev": true,
       "inBundle": true,
       "license": "Apache-2.0",
       "optional": true,
@@ -11964,6 +11767,7 @@
     },
     "node_modules/fsevents/node_modules/fs-minipass": {
       "version": "1.2.5",
+      "dev": true,
       "inBundle": true,
       "license": "ISC",
       "optional": true,
@@ -11973,12 +11777,14 @@
     },
     "node_modules/fsevents/node_modules/fs.realpath": {
       "version": "1.0.0",
+      "dev": true,
       "inBundle": true,
       "license": "ISC",
       "optional": true
     },
     "node_modules/fsevents/node_modules/gauge": {
       "version": "2.7.4",
+      "dev": true,
       "inBundle": true,
       "license": "ISC",
       "optional": true,
@@ -11995,6 +11801,7 @@
     },
     "node_modules/fsevents/node_modules/glob": {
       "version": "7.1.3",
+      "dev": true,
       "inBundle": true,
       "license": "ISC",
       "optional": true,
@@ -12012,12 +11819,14 @@
     },
     "node_modules/fsevents/node_modules/has-unicode": {
       "version": "2.0.1",
+      "dev": true,
       "inBundle": true,
       "license": "ISC",
       "optional": true
     },
     "node_modules/fsevents/node_modules/iconv-lite": {
       "version": "0.4.24",
+      "dev": true,
       "inBundle": true,
       "license": "MIT",
       "optional": true,
@@ -12030,6 +11839,7 @@
     },
     "node_modules/fsevents/node_modules/ignore-walk": {
       "version": "3.0.1",
+      "dev": true,
       "inBundle": true,
       "license": "ISC",
       "optional": true,
@@ -12039,6 +11849,7 @@
     },
     "node_modules/fsevents/node_modules/inflight": {
       "version": "1.0.6",
+      "dev": true,
       "inBundle": true,
       "license": "ISC",
       "optional": true,
@@ -12049,12 +11860,14 @@
     },
     "node_modules/fsevents/node_modules/inherits": {
       "version": "2.0.3",
+      "dev": true,
       "inBundle": true,
       "license": "ISC",
       "optional": true
     },
     "node_modules/fsevents/node_modules/ini": {
       "version": "1.3.5",
+      "dev": true,
       "inBundle": true,
       "license": "ISC",
       "optional": true,
@@ -12064,6 +11877,7 @@
     },
     "node_modules/fsevents/node_modules/is-fullwidth-code-point": {
       "version": "1.0.0",
+      "dev": true,
       "inBundle": true,
       "license": "MIT",
       "optional": true,
@@ -12076,12 +11890,14 @@
     },
     "node_modules/fsevents/node_modules/isarray": {
       "version": "1.0.0",
+      "dev": true,
       "inBundle": true,
       "license": "MIT",
       "optional": true
     },
     "node_modules/fsevents/node_modules/minimatch": {
       "version": "3.0.4",
+      "dev": true,
       "inBundle": true,
       "license": "ISC",
       "optional": true,
@@ -12094,12 +11910,14 @@
     },
     "node_modules/fsevents/node_modules/minimist": {
       "version": "0.0.8",
+      "dev": true,
       "inBundle": true,
       "license": "MIT",
       "optional": true
     },
     "node_modules/fsevents/node_modules/minipass": {
       "version": "2.3.5",
+      "dev": true,
       "inBundle": true,
       "license": "ISC",
       "optional": true,
@@ -12110,6 +11928,7 @@
     },
     "node_modules/fsevents/node_modules/minizlib": {
       "version": "1.2.1",
+      "dev": true,
       "inBundle": true,
       "license": "MIT",
       "optional": true,
@@ -12119,6 +11938,7 @@
     },
     "node_modules/fsevents/node_modules/mkdirp": {
       "version": "0.5.1",
+      "dev": true,
       "inBundle": true,
       "license": "MIT",
       "optional": true,
@@ -12131,12 +11951,14 @@
     },
     "node_modules/fsevents/node_modules/ms": {
       "version": "2.1.1",
+      "dev": true,
       "inBundle": true,
       "license": "MIT",
       "optional": true
     },
     "node_modules/fsevents/node_modules/needle": {
       "version": "2.3.0",
+      "dev": true,
       "inBundle": true,
       "license": "MIT",
       "optional": true,
@@ -12154,6 +11976,7 @@
     },
     "node_modules/fsevents/node_modules/node-pre-gyp": {
       "version": "0.12.0",
+      "dev": true,
       "inBundle": true,
       "license": "BSD-3-Clause",
       "optional": true,
@@ -12175,6 +11998,7 @@
     },
     "node_modules/fsevents/node_modules/nopt": {
       "version": "4.0.1",
+      "dev": true,
       "inBundle": true,
       "license": "ISC",
       "optional": true,
@@ -12188,12 +12012,14 @@
     },
     "node_modules/fsevents/node_modules/npm-bundled": {
       "version": "1.0.6",
+      "dev": true,
       "inBundle": true,
       "license": "ISC",
       "optional": true
     },
     "node_modules/fsevents/node_modules/npm-packlist": {
       "version": "1.4.1",
+      "dev": true,
       "inBundle": true,
       "license": "ISC",
       "optional": true,
@@ -12204,6 +12030,7 @@
     },
     "node_modules/fsevents/node_modules/npmlog": {
       "version": "4.1.2",
+      "dev": true,
       "inBundle": true,
       "license": "ISC",
       "optional": true,
@@ -12216,6 +12043,7 @@
     },
     "node_modules/fsevents/node_modules/number-is-nan": {
       "version": "1.0.1",
+      "dev": true,
       "inBundle": true,
       "license": "MIT",
       "optional": true,
@@ -12225,6 +12053,7 @@
     },
     "node_modules/fsevents/node_modules/object-assign": {
       "version": "4.1.1",
+      "dev": true,
       "inBundle": true,
       "license": "MIT",
       "optional": true,
@@ -12234,6 +12063,7 @@
     },
     "node_modules/fsevents/node_modules/once": {
       "version": "1.4.0",
+      "dev": true,
       "inBundle": true,
       "license": "ISC",
       "optional": true,
@@ -12243,6 +12073,7 @@
     },
     "node_modules/fsevents/node_modules/os-homedir": {
       "version": "1.0.2",
+      "dev": true,
       "inBundle": true,
       "license": "MIT",
       "optional": true,
@@ -12252,6 +12083,7 @@
     },
     "node_modules/fsevents/node_modules/os-tmpdir": {
       "version": "1.0.2",
+      "dev": true,
       "inBundle": true,
       "license": "MIT",
       "optional": true,
@@ -12261,6 +12093,7 @@
     },
     "node_modules/fsevents/node_modules/osenv": {
       "version": "0.1.5",
+      "dev": true,
       "inBundle": true,
       "license": "ISC",
       "optional": true,
@@ -12271,6 +12104,7 @@
     },
     "node_modules/fsevents/node_modules/path-is-absolute": {
       "version": "1.0.1",
+      "dev": true,
       "inBundle": true,
       "license": "MIT",
       "optional": true,
@@ -12280,12 +12114,14 @@
     },
     "node_modules/fsevents/node_modules/process-nextick-args": {
       "version": "2.0.0",
+      "dev": true,
       "inBundle": true,
       "license": "MIT",
       "optional": true
     },
     "node_modules/fsevents/node_modules/rc": {
       "version": "1.2.8",
+      "dev": true,
       "inBundle": true,
       "license": "(BSD-2-Clause OR MIT OR Apache-2.0)",
       "optional": true,
@@ -12301,12 +12137,14 @@
     },
     "node_modules/fsevents/node_modules/rc/node_modules/minimist": {
       "version": "1.2.0",
+      "dev": true,
       "inBundle": true,
       "license": "MIT",
       "optional": true
     },
     "node_modules/fsevents/node_modules/readable-stream": {
       "version": "2.3.6",
+      "dev": true,
       "inBundle": true,
       "license": "MIT",
       "optional": true,
@@ -12322,6 +12160,7 @@
     },
     "node_modules/fsevents/node_modules/rimraf": {
       "version": "2.6.3",
+      "dev": true,
       "inBundle": true,
       "license": "ISC",
       "optional": true,
@@ -12334,24 +12173,28 @@
     },
     "node_modules/fsevents/node_modules/safe-buffer": {
       "version": "5.1.2",
+      "dev": true,
       "inBundle": true,
       "license": "MIT",
       "optional": true
     },
     "node_modules/fsevents/node_modules/safer-buffer": {
       "version": "2.1.2",
+      "dev": true,
       "inBundle": true,
       "license": "MIT",
       "optional": true
     },
     "node_modules/fsevents/node_modules/sax": {
       "version": "1.2.4",
+      "dev": true,
       "inBundle": true,
       "license": "ISC",
       "optional": true
     },
     "node_modules/fsevents/node_modules/semver": {
       "version": "5.7.0",
+      "dev": true,
       "inBundle": true,
       "license": "ISC",
       "optional": true,
@@ -12361,18 +12204,21 @@
     },
     "node_modules/fsevents/node_modules/set-blocking": {
       "version": "2.0.0",
+      "dev": true,
       "inBundle": true,
       "license": "ISC",
       "optional": true
     },
     "node_modules/fsevents/node_modules/signal-exit": {
       "version": "3.0.2",
+      "dev": true,
       "inBundle": true,
       "license": "ISC",
       "optional": true
     },
     "node_modules/fsevents/node_modules/string_decoder": {
       "version": "1.1.1",
+      "dev": true,
       "inBundle": true,
       "license": "MIT",
       "optional": true,
@@ -12382,6 +12228,7 @@
     },
     "node_modules/fsevents/node_modules/string-width": {
       "version": "1.0.2",
+      "dev": true,
       "inBundle": true,
       "license": "MIT",
       "optional": true,
@@ -12396,6 +12243,7 @@
     },
     "node_modules/fsevents/node_modules/strip-ansi": {
       "version": "3.0.1",
+      "dev": true,
       "inBundle": true,
       "license": "MIT",
       "optional": true,
@@ -12408,6 +12256,7 @@
     },
     "node_modules/fsevents/node_modules/strip-json-comments": {
       "version": "2.0.1",
+      "dev": true,
       "inBundle": true,
       "license": "MIT",
       "optional": true,
@@ -12417,6 +12266,7 @@
     },
     "node_modules/fsevents/node_modules/tar": {
       "version": "4.4.8",
+      "dev": true,
       "inBundle": true,
       "license": "ISC",
       "optional": true,
@@ -12435,12 +12285,14 @@
     },
     "node_modules/fsevents/node_modules/util-deprecate": {
       "version": "1.0.2",
+      "dev": true,
       "inBundle": true,
       "license": "MIT",
       "optional": true
     },
     "node_modules/fsevents/node_modules/wide-align": {
       "version": "1.1.3",
+      "dev": true,
       "inBundle": true,
       "license": "ISC",
       "optional": true,
@@ -12450,12 +12302,14 @@
     },
     "node_modules/fsevents/node_modules/wrappy": {
       "version": "1.0.2",
+      "dev": true,
       "inBundle": true,
       "license": "ISC",
       "optional": true
     },
     "node_modules/fsevents/node_modules/yallist": {
       "version": "3.0.3",
+      "dev": true,
       "inBundle": true,
       "license": "ISC",
       "optional": true
@@ -13021,15 +12875,6 @@
         "wbuf": "^1.1.0"
       }
     },
-    "node_modules/html-element-map": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/html-element-map/-/html-element-map-1.1.0.tgz",
-      "integrity": "sha512-iqiG3dTZmy+uUaTmHarTL+3/A2VW9ox/9uasKEZC+R/wAtUrTcRlXPSaPqsnWPfIu8wqn09jQNwMRqzL54jSYA==",
-      "dev": true,
-      "dependencies": {
-        "array-filter": "^1.0.0"
-      }
-    },
     "node_modules/html-encoding-sniffer": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz",
@@ -13053,34 +12898,6 @@
       "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
       "dev": true
     },
-    "node_modules/htmlparser2": {
-      "version": "3.10.1",
-      "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz",
-      "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==",
-      "dev": true,
-      "dependencies": {
-        "domelementtype": "^1.3.1",
-        "domhandler": "^2.3.0",
-        "domutils": "^1.5.1",
-        "entities": "^1.1.1",
-        "inherits": "^2.0.1",
-        "readable-stream": "^3.1.1"
-      }
-    },
-    "node_modules/htmlparser2/node_modules/readable-stream": {
-      "version": "3.4.0",
-      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz",
-      "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==",
-      "dev": true,
-      "dependencies": {
-        "inherits": "^2.0.3",
-        "string_decoder": "^1.1.1",
-        "util-deprecate": "^1.0.1"
-      },
-      "engines": {
-        "node": ">= 6"
-      }
-    },
     "node_modules/http-deceiver": {
       "version": "1.2.7",
       "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz",
@@ -14100,8 +13917,7 @@
     "node_modules/is-plain-obj": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
-      "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=",
-      "dev": true,
+      "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==",
       "engines": {
         "node": ">=0.10.0"
       }
@@ -14191,12 +14007,6 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
-    "node_modules/is-subset": {
-      "version": "0.1.1",
-      "resolved": "https://registry.npmjs.org/is-subset/-/is-subset-0.1.1.tgz",
-      "integrity": "sha1-ilkRfZMt4d4A8kX83TnOQ/HpOaY=",
-      "dev": true
-    },
     "node_modules/is-symbol": {
       "version": "1.0.4",
       "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz",
@@ -18084,15 +17894,6 @@
         "node": ">= 10.14.2"
       }
     },
-    "node_modules/jest-serializer-html": {
-      "version": "7.0.0",
-      "resolved": "https://registry.npmjs.org/jest-serializer-html/-/jest-serializer-html-7.0.0.tgz",
-      "integrity": "sha512-o3S2j/5yA9emV8+QRHqJ41SznW5cZ1PXIAk+aSToJffdhuaiSoDsa4IgqV8lNOHPp4cP0LNT7k5KjXjD+l6SGg==",
-      "dev": true,
-      "dependencies": {
-        "diffable-html": "^4.0.0"
-      }
-    },
     "node_modules/jest-snapshot": {
       "version": "26.6.0",
       "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-26.6.0.tgz",
@@ -20382,24 +20183,12 @@
       "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz",
       "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ=="
     },
-    "node_modules/lodash.escape": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-4.0.1.tgz",
-      "integrity": "sha1-yQRGkMIeBClL6qUXcS/e0fqI3pg=",
-      "dev": true
-    },
     "node_modules/lodash.find": {
       "version": "4.6.0",
       "resolved": "https://registry.npmjs.org/lodash.find/-/lodash.find-4.6.0.tgz",
       "integrity": "sha1-ywcE1Hq3F4n/oN6Ll92Sb7iLE7E=",
       "dev": true
     },
-    "node_modules/lodash.flattendeep": {
-      "version": "4.4.0",
-      "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz",
-      "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=",
-      "dev": true
-    },
     "node_modules/lodash.get": {
       "version": "4.4.2",
       "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
@@ -20418,12 +20207,6 @@
       "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=",
       "dev": true
     },
-    "node_modules/lodash.isequal": {
-      "version": "4.5.0",
-      "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
-      "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=",
-      "dev": true
-    },
     "node_modules/lodash.isinteger": {
       "version": "4.0.4",
       "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
@@ -21263,12 +21046,6 @@
         "mkdirp": "bin/cmd.js"
       }
     },
-    "node_modules/moo": {
-      "version": "0.4.3",
-      "resolved": "https://registry.npmjs.org/moo/-/moo-0.4.3.tgz",
-      "integrity": "sha512-gFD2xGCl8YFgGHsqJ9NKRVdwlioeW3mI1iqfLNYQOv0+6JRwG58Zk9DIGQgyIaffSYaO1xsKnMaYzzNr1KyIAw==",
-      "dev": true
-    },
     "node_modules/mri": {
       "version": "1.1.4",
       "resolved": "https://registry.npmjs.org/mri/-/mri-1.1.4.tgz",
@@ -21341,40 +21118,6 @@
       "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
       "devOptional": true
     },
-    "node_modules/nearley": {
-      "version": "2.19.0",
-      "resolved": "https://registry.npmjs.org/nearley/-/nearley-2.19.0.tgz",
-      "integrity": "sha512-2v52FTw7RPqieZr3Gth1luAXZR7Je6q3KaDHY5bjl/paDUdMu35fZ8ICNgiYJRr3tf3NMvIQQR1r27AvEr9CRA==",
-      "dev": true,
-      "dependencies": {
-        "commander": "^2.19.0",
-        "moo": "^0.4.3",
-        "railroad-diagrams": "^1.0.0",
-        "randexp": "0.4.6",
-        "semver": "^5.4.1"
-      },
-      "bin": {
-        "nearley-railroad": "bin/nearley-railroad.js",
-        "nearley-test": "bin/nearley-test.js",
-        "nearley-unparse": "bin/nearley-unparse.js",
-        "nearleyc": "bin/nearleyc.js"
-      }
-    },
-    "node_modules/nearley/node_modules/commander": {
-      "version": "2.20.3",
-      "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
-      "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
-      "dev": true
-    },
-    "node_modules/nearley/node_modules/semver": {
-      "version": "5.7.1",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
-      "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
-      "dev": true,
-      "bin": {
-        "semver": "bin/semver"
-      }
-    },
     "node_modules/negotiator": {
       "version": "0.6.3",
       "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
@@ -21559,15 +21302,6 @@
         "node": ">=4"
       }
     },
-    "node_modules/nth-check": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz",
-      "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==",
-      "dev": true,
-      "dependencies": {
-        "boolbase": "~1.0.0"
-      }
-    },
     "node_modules/nwsapi": {
       "version": "2.2.0",
       "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz",
@@ -21638,22 +21372,6 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
-    "node_modules/object-is": {
-      "version": "1.1.5",
-      "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz",
-      "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==",
-      "dev": true,
-      "dependencies": {
-        "call-bind": "^1.0.2",
-        "define-properties": "^1.1.3"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
     "node_modules/object-keys": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
@@ -21736,21 +21454,6 @@
         "node": ">=0.10.0"
       }
     },
-    "node_modules/object.values": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.0.tgz",
-      "integrity": "sha512-8mf0nKLAoFX6VlNVdhGj31SVYpaNFtUnuoOXWyFEstsWRgU837AK+JYM0iAxwkSzGRbwn8cbFmgbyxj1j4VbXg==",
-      "dev": true,
-      "dependencies": {
-        "define-properties": "^1.1.3",
-        "es-abstract": "^1.12.0",
-        "function-bind": "^1.1.1",
-        "has": "^1.0.3"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      }
-    },
     "node_modules/obuf": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz",
@@ -22114,15 +21817,6 @@
         "node": ">=0.10.0"
       }
     },
-    "node_modules/parse5": {
-      "version": "3.0.3",
-      "resolved": "https://registry.npmjs.org/parse5/-/parse5-3.0.3.tgz",
-      "integrity": "sha512-rgO9Zg5LLLkfJF9E6CCmXlSE4UVceloys8JrFqCcHloC3usd/kJCyPDwH2SOlzix2j3xaP9sUX3e8+kvkuleAA==",
-      "dev": true,
-      "dependencies": {
-        "@types/node": "*"
-      }
-    },
     "node_modules/parseurl": {
       "version": "1.3.3",
       "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
@@ -22778,25 +22472,6 @@
         "performance-now": "^2.1.0"
       }
     },
-    "node_modules/railroad-diagrams": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz",
-      "integrity": "sha1-635iZ1SN3t+4mcG5Dlc3RVnN234=",
-      "dev": true
-    },
-    "node_modules/randexp": {
-      "version": "0.4.6",
-      "resolved": "https://registry.npmjs.org/randexp/-/randexp-0.4.6.tgz",
-      "integrity": "sha512-80WNmd9DA0tmZrw9qQa62GPPWfuXJknrmVmLcxvq4uZBdYqb1wYoKTmnlGUchvVWe0XiLupYkBoXVOxz3C8DYQ==",
-      "dev": true,
-      "dependencies": {
-        "discontinuous-range": "1.0.0",
-        "ret": "~0.1.10"
-      },
-      "engines": {
-        "node": ">=0.12"
-      }
-    },
     "node_modules/randombytes": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
@@ -24003,16 +23678,6 @@
         "rimraf": "bin.js"
       }
     },
-    "node_modules/rst-selector-parser": {
-      "version": "2.2.3",
-      "resolved": "https://registry.npmjs.org/rst-selector-parser/-/rst-selector-parser-2.2.3.tgz",
-      "integrity": "sha1-gbIw6i/MYGbInjRy3nlChdmwPZE=",
-      "dev": true,
-      "dependencies": {
-        "lodash.flattendeep": "^4.4.0",
-        "nearley": "^2.7.10"
-      }
-    },
     "node_modules/rsvp": {
       "version": "4.8.5",
       "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz",
@@ -24980,20 +24645,6 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
-    "node_modules/string.prototype.trim": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.0.tgz",
-      "integrity": "sha512-9EIjYD/WdlvLpn987+ctkLf0FfvBefOCuiEr2henD8X+7jfwPnyvTdmW8OJhj5p+M0/96mBdynLWkxUr+rHlpg==",
-      "dev": true,
-      "dependencies": {
-        "define-properties": "^1.1.3",
-        "es-abstract": "^1.13.0",
-        "function-bind": "^1.1.1"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      }
-    },
     "node_modules/string.prototype.trimend": {
       "version": "1.0.5",
       "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz",
@@ -31070,15 +30721,6 @@
         "magic-string": "^0.25.0"
       }
     },
-    "@types/cheerio": {
-      "version": "0.22.13",
-      "resolved": "https://registry.npmjs.org/@types/cheerio/-/cheerio-0.22.13.tgz",
-      "integrity": "sha512-OZd7dCUOUkiTorf97vJKwZnSja/DmHfuBAroe1kREZZTCf/tlFecwHhsOos3uVHxeKGZDwzolIrCUApClkdLuA==",
-      "dev": true,
-      "requires": {
-        "@types/node": "*"
-      }
-    },
     "@types/connect": {
       "version": "3.4.33",
       "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.33.tgz",
@@ -31113,16 +30755,6 @@
       "integrity": "sha1-6JLSk8ksnB0/mvcsFaVU+8fgiVo=",
       "dev": true
     },
-    "@types/enzyme": {
-      "version": "3.10.3",
-      "resolved": "https://registry.npmjs.org/@types/enzyme/-/enzyme-3.10.3.tgz",
-      "integrity": "sha512-f/Kcb84sZOSZiBPCkr4He9/cpuSLcKRyQaEE20Q30Prx0Dn6wcyMAWI0yofL6yvd9Ht9G7EVkQeRqK0n5w8ILw==",
-      "dev": true,
-      "requires": {
-        "@types/cheerio": "*",
-        "@types/react": "*"
-      }
-    },
     "@types/escodegen": {
       "version": "0.0.6",
       "resolved": "https://registry.npmjs.org/@types/escodegen/-/escodegen-0.0.6.tgz",
@@ -31338,8 +30970,7 @@
     "@types/prop-types": {
       "version": "15.7.3",
       "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz",
-      "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==",
-      "dev": true
+      "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw=="
     },
     "@types/qs": {
       "version": "6.9.5",
@@ -31370,11 +31001,41 @@
         "@types/react": "*"
       }
     },
+    "@types/react-test-renderer": {
+      "version": "17.0.2",
+      "resolved": "https://registry.npmjs.org/@types/react-test-renderer/-/react-test-renderer-17.0.2.tgz",
+      "integrity": "sha512-+F1KONQTBHDBBhbHuT2GNydeMpPuviduXIVJRB7Y4nma4NR5DrTJfMMZ+jbhEHbpwL+Uqhs1WXh4KHiyrtYTPg==",
+      "requires": {
+        "@types/react": "^17"
+      },
+      "dependencies": {
+        "@types/react": {
+          "version": "17.0.50",
+          "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.50.tgz",
+          "integrity": "sha512-ZCBHzpDb5skMnc1zFXAXnL3l1FAdi+xZvwxK+PkglMmBrwjpp9nKaWuEvrGnSifCJmBFGxZOOFuwC6KH/s0NuA==",
+          "requires": {
+            "@types/prop-types": "*",
+            "@types/scheduler": "*",
+            "csstype": "^3.0.2"
+          }
+        },
+        "csstype": {
+          "version": "3.1.1",
+          "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz",
+          "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw=="
+        }
+      }
+    },
     "@types/retry": {
       "version": "0.12.1",
       "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.1.tgz",
       "integrity": "sha512-xoDlM2S4ortawSWORYqsdU+2rxdh4LRW9ytc3zmT37RIKQh6IHyKwwtKhKis9ah8ol07DCkZxPt8BBvPjC6v4g=="
     },
+    "@types/scheduler": {
+      "version": "0.16.2",
+      "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz",
+      "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew=="
+    },
     "@types/serve-index": {
       "version": "1.9.1",
       "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz",
@@ -31896,40 +31557,6 @@
       "dev": true,
       "requires": {}
     },
-    "@wojtekmaj/enzyme-adapter-react-17": {
-      "version": "0.6.7",
-      "resolved": "https://registry.npmjs.org/@wojtekmaj/enzyme-adapter-react-17/-/enzyme-adapter-react-17-0.6.7.tgz",
-      "integrity": "sha512-B+byiwi/T1bx5hcj9wc0fUL5Hlb5giSXJzcnEfJVl2j6dGV2NJfcxDBYX0WWwIxlzNiFz8kAvlkFWI2y/nscZQ==",
-      "dev": true,
-      "requires": {
-        "@wojtekmaj/enzyme-adapter-utils": "^0.1.4",
-        "enzyme-shallow-equal": "^1.0.0",
-        "has": "^1.0.0",
-        "prop-types": "^15.7.0",
-        "react-is": "^17.0.0",
-        "react-test-renderer": "^17.0.0"
-      },
-      "dependencies": {
-        "react-is": {
-          "version": "17.0.2",
-          "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
-          "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
-          "dev": true
-        }
-      }
-    },
-    "@wojtekmaj/enzyme-adapter-utils": {
-      "version": "0.1.4",
-      "resolved": "https://registry.npmjs.org/@wojtekmaj/enzyme-adapter-utils/-/enzyme-adapter-utils-0.1.4.tgz",
-      "integrity": "sha512-ARGIQSIIv3oBia1m5Ihn1VU0FGmft6KPe39SBKTb8p7LSXO23YI4kNtc4M/cKoIY7P+IYdrZcgMObvedyjoSQA==",
-      "dev": true,
-      "requires": {
-        "function.prototype.name": "^1.1.0",
-        "has": "^1.0.0",
-        "object.fromentries": "^2.0.0",
-        "prop-types": "^15.7.0"
-      }
-    },
     "@xtuc/ieee754": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
@@ -32182,12 +31809,6 @@
       "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=",
       "dev": true
     },
-    "array-filter": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-1.0.0.tgz",
-      "integrity": "sha1-uveeYubvTCpMC4MSMtr/7CUfnYM=",
-      "dev": true
-    },
     "array-find-index": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz",
@@ -32229,17 +31850,6 @@
       "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=",
       "dev": true
     },
-    "array.prototype.flat": {
-      "version": "1.2.2",
-      "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.2.tgz",
-      "integrity": "sha512-VXjh7lAL4KXKF2hY4FnEW9eRW6IhdvFW1sN/JwLbmECbCgACCnBHNyP3lFiYuttr0jxRN9Bsc5+G27dMseSWqQ==",
-      "dev": true,
-      "requires": {
-        "define-properties": "^1.1.3",
-        "es-abstract": "^1.15.0",
-        "function-bind": "^1.1.1"
-      }
-    },
     "array.prototype.flatmap": {
       "version": "1.2.3",
       "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.3.tgz",
@@ -32738,12 +32348,6 @@
         "multicast-dns": "^7.2.4"
       }
     },
-    "boolbase": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
-      "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=",
-      "dev": true
-    },
     "brace-expansion": {
       "version": "1.1.11",
       "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@@ -32974,20 +32578,6 @@
       "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz",
       "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg=="
     },
-    "cheerio": {
-      "version": "1.0.0-rc.3",
-      "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.3.tgz",
-      "integrity": "sha512-0td5ijfUPuubwLUu0OBoe98gZj8C/AA+RW3v67GPlGOrvxWjZmBXiBCRU+I8VEiNyJzjth40POfHiz2RB3gImA==",
-      "dev": true,
-      "requires": {
-        "css-select": "~1.2.0",
-        "dom-serializer": "~0.1.1",
-        "entities": "~1.1.1",
-        "htmlparser2": "^3.9.1",
-        "lodash": "^4.15.0",
-        "parse5": "^3.0.1"
-      }
-    },
     "chokidar": {
       "version": "2.1.8",
       "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz",
@@ -33640,24 +33230,6 @@
         }
       }
     },
-    "css-select": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz",
-      "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=",
-      "dev": true,
-      "requires": {
-        "boolbase": "~1.0.0",
-        "css-what": "2.1",
-        "domutils": "1.5.1",
-        "nth-check": "~1.0.1"
-      }
-    },
-    "css-what": {
-      "version": "2.1.3",
-      "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz",
-      "integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==",
-      "dev": true
-    },
     "css.escape": {
       "version": "1.5.1",
       "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz",
@@ -34163,15 +33735,6 @@
       "integrity": "sha512-Hq8o7+6GaZeoFjtpgvRBUknSXNeJiCx7V9Fr94ZMljNiCr9n9L8H8aJqgWOQiDDGdyn29fRNcDdRVJ5fdyihfg==",
       "dev": true
     },
-    "diffable-html": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/diffable-html/-/diffable-html-4.0.0.tgz",
-      "integrity": "sha512-keJdgy2qBkdrrnwP1YE6e834d4Y+mV0aRFzk8w7WzyAJVbQVfcJltSmUWB3r/NOoO/0jt7RdJlvy5ioyqvmQcw==",
-      "dev": true,
-      "requires": {
-        "htmlparser2": "^3.9.2"
-      }
-    },
     "dir-glob": {
       "version": "3.0.1",
       "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
@@ -34187,12 +33750,6 @@
         }
       }
     },
-    "discontinuous-range": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/discontinuous-range/-/discontinuous-range-1.0.0.tgz",
-      "integrity": "sha1-44Mx8IRLukm5qctxx3FYWqsbxlo=",
-      "dev": true
-    },
     "dns-equal": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz",
@@ -34230,22 +33787,6 @@
       "integrity": "sha512-TvrjBckDy2c6v6RLxPv5QXOnU+SmF9nBII5621Ve5fu6Z/BDrENurBEvlC1f44lKEUVqOpK4w9E5Idc5/EgkLQ==",
       "dev": true
     },
-    "dom-serializer": {
-      "version": "0.1.1",
-      "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz",
-      "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==",
-      "dev": true,
-      "requires": {
-        "domelementtype": "^1.3.0",
-        "entities": "^1.1.1"
-      }
-    },
-    "domelementtype": {
-      "version": "1.3.1",
-      "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz",
-      "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==",
-      "dev": true
-    },
     "domexception": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz",
@@ -34263,25 +33804,6 @@
         }
       }
     },
-    "domhandler": {
-      "version": "2.4.2",
-      "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz",
-      "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==",
-      "dev": true,
-      "requires": {
-        "domelementtype": "1"
-      }
-    },
-    "domutils": {
-      "version": "1.5.1",
-      "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz",
-      "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=",
-      "dev": true,
-      "requires": {
-        "dom-serializer": "0",
-        "domelementtype": "1"
-      }
-    },
     "duplexer": {
       "version": "0.1.2",
       "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz",
@@ -34380,66 +33902,12 @@
         }
       }
     },
-    "entities": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz",
-      "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==",
-      "dev": true
-    },
     "envinfo": {
       "version": "7.8.1",
       "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz",
       "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==",
       "dev": true
     },
-    "enzyme": {
-      "version": "3.10.0",
-      "resolved": "https://registry.npmjs.org/enzyme/-/enzyme-3.10.0.tgz",
-      "integrity": "sha512-p2yy9Y7t/PFbPoTvrWde7JIYB2ZyGC+NgTNbVEGvZ5/EyoYSr9aG/2rSbVvyNvMHEhw9/dmGUJHWtfQIEiX9pg==",
-      "dev": true,
-      "requires": {
-        "array.prototype.flat": "^1.2.1",
-        "cheerio": "^1.0.0-rc.2",
-        "function.prototype.name": "^1.1.0",
-        "has": "^1.0.3",
-        "html-element-map": "^1.0.0",
-        "is-boolean-object": "^1.0.0",
-        "is-callable": "^1.1.4",
-        "is-number-object": "^1.0.3",
-        "is-regex": "^1.0.4",
-        "is-string": "^1.0.4",
-        "is-subset": "^0.1.1",
-        "lodash.escape": "^4.0.1",
-        "lodash.isequal": "^4.5.0",
-        "object-inspect": "^1.6.0",
-        "object-is": "^1.0.1",
-        "object.assign": "^4.1.0",
-        "object.entries": "^1.0.4",
-        "object.values": "^1.0.4",
-        "raf": "^3.4.0",
-        "rst-selector-parser": "^2.2.3",
-        "string.prototype.trim": "^1.1.2"
-      }
-    },
-    "enzyme-shallow-equal": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/enzyme-shallow-equal/-/enzyme-shallow-equal-1.0.4.tgz",
-      "integrity": "sha512-MttIwB8kKxypwHvRynuC3ahyNc+cFbR8mjVIltnmzQ0uKGqmsfO4bfBuLxb0beLNPhjblUEYvEbsg+VSygvF1Q==",
-      "dev": true,
-      "requires": {
-        "has": "^1.0.3",
-        "object-is": "^1.1.2"
-      }
-    },
-    "enzyme-to-json": {
-      "version": "3.4.3",
-      "resolved": "https://registry.npmjs.org/enzyme-to-json/-/enzyme-to-json-3.4.3.tgz",
-      "integrity": "sha512-jqNEZlHqLdz7OTpXSzzghArSS3vigj67IU/fWkPyl1c0TCj9P5s6Ze0kRkYZWNEoCqCR79xlQbigYlMx5erh8A==",
-      "dev": true,
-      "requires": {
-        "lodash": "^4.17.15"
-      }
-    },
     "error-ex": {
       "version": "1.3.2",
       "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
@@ -34528,7 +33996,7 @@
     "escape-string-regexp": {
       "version": "1.0.5",
       "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
-      "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
+      "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="
     },
     "escodegen": {
       "version": "1.12.0",
@@ -36217,21 +35685,25 @@
         "abbrev": {
           "version": "1.1.1",
           "bundled": true,
+          "dev": true,
           "optional": true
         },
         "ansi-regex": {
           "version": "2.1.1",
           "bundled": true,
+          "dev": true,
           "optional": true
         },
         "aproba": {
           "version": "1.2.0",
           "bundled": true,
+          "dev": true,
           "optional": true
         },
         "are-we-there-yet": {
           "version": "1.1.5",
           "bundled": true,
+          "dev": true,
           "optional": true,
           "requires": {
             "delegates": "^1.0.0",
@@ -36241,11 +35713,13 @@
         "balanced-match": {
           "version": "1.0.0",
           "bundled": true,
+          "dev": true,
           "optional": true
         },
         "brace-expansion": {
           "version": "1.1.11",
           "bundled": true,
+          "dev": true,
           "optional": true,
           "requires": {
             "balanced-match": "^1.0.0",
@@ -36255,31 +35729,37 @@
         "chownr": {
           "version": "1.1.1",
           "bundled": true,
+          "dev": true,
           "optional": true
         },
         "code-point-at": {
           "version": "1.1.0",
           "bundled": true,
+          "dev": true,
           "optional": true
         },
         "concat-map": {
           "version": "0.0.1",
           "bundled": true,
+          "dev": true,
           "optional": true
         },
         "console-control-strings": {
           "version": "1.1.0",
           "bundled": true,
+          "dev": true,
           "optional": true
         },
         "core-util-is": {
           "version": "1.0.2",
           "bundled": true,
+          "dev": true,
           "optional": true
         },
         "debug": {
           "version": "4.1.1",
           "bundled": true,
+          "dev": true,
           "optional": true,
           "requires": {
             "ms": "^2.1.1"
@@ -36288,21 +35768,25 @@
         "deep-extend": {
           "version": "0.6.0",
           "bundled": true,
+          "dev": true,
           "optional": true
         },
         "delegates": {
           "version": "1.0.0",
           "bundled": true,
+          "dev": true,
           "optional": true
         },
         "detect-libc": {
           "version": "1.0.3",
           "bundled": true,
+          "dev": true,
           "optional": true
         },
         "fs-minipass": {
           "version": "1.2.5",
           "bundled": true,
+          "dev": true,
           "optional": true,
           "requires": {
             "minipass": "^2.2.1"
@@ -36311,11 +35795,13 @@
         "fs.realpath": {
           "version": "1.0.0",
           "bundled": true,
+          "dev": true,
           "optional": true
         },
         "gauge": {
           "version": "2.7.4",
           "bundled": true,
+          "dev": true,
           "optional": true,
           "requires": {
             "aproba": "^1.0.3",
@@ -36331,6 +35817,7 @@
         "glob": {
           "version": "7.1.3",
           "bundled": true,
+          "dev": true,
           "optional": true,
           "requires": {
             "fs.realpath": "^1.0.0",
@@ -36344,11 +35831,13 @@
         "has-unicode": {
           "version": "2.0.1",
           "bundled": true,
+          "dev": true,
           "optional": true
         },
         "iconv-lite": {
           "version": "0.4.24",
           "bundled": true,
+          "dev": true,
           "optional": true,
           "requires": {
             "safer-buffer": ">= 2.1.2 < 3"
@@ -36357,6 +35846,7 @@
         "ignore-walk": {
           "version": "3.0.1",
           "bundled": true,
+          "dev": true,
           "optional": true,
           "requires": {
             "minimatch": "^3.0.4"
@@ -36365,6 +35855,7 @@
         "inflight": {
           "version": "1.0.6",
           "bundled": true,
+          "dev": true,
           "optional": true,
           "requires": {
             "once": "^1.3.0",
@@ -36374,16 +35865,19 @@
         "inherits": {
           "version": "2.0.3",
           "bundled": true,
+          "dev": true,
           "optional": true
         },
         "ini": {
           "version": "1.3.5",
           "bundled": true,
+          "dev": true,
           "optional": true
         },
         "is-fullwidth-code-point": {
           "version": "1.0.0",
           "bundled": true,
+          "dev": true,
           "optional": true,
           "requires": {
             "number-is-nan": "^1.0.0"
@@ -36392,11 +35886,13 @@
         "isarray": {
           "version": "1.0.0",
           "bundled": true,
+          "dev": true,
           "optional": true
         },
         "minimatch": {
           "version": "3.0.4",
           "bundled": true,
+          "dev": true,
           "optional": true,
           "requires": {
             "brace-expansion": "^1.1.7"
@@ -36405,11 +35901,13 @@
         "minimist": {
           "version": "0.0.8",
           "bundled": true,
+          "dev": true,
           "optional": true
         },
         "minipass": {
           "version": "2.3.5",
           "bundled": true,
+          "dev": true,
           "optional": true,
           "requires": {
             "safe-buffer": "^5.1.2",
@@ -36419,6 +35917,7 @@
         "minizlib": {
           "version": "1.2.1",
           "bundled": true,
+          "dev": true,
           "optional": true,
           "requires": {
             "minipass": "^2.2.1"
@@ -36427,6 +35926,7 @@
         "mkdirp": {
           "version": "0.5.1",
           "bundled": true,
+          "dev": true,
           "optional": true,
           "requires": {
             "minimist": "0.0.8"
@@ -36435,11 +35935,13 @@
         "ms": {
           "version": "2.1.1",
           "bundled": true,
+          "dev": true,
           "optional": true
         },
         "needle": {
           "version": "2.3.0",
           "bundled": true,
+          "dev": true,
           "optional": true,
           "requires": {
             "debug": "^4.1.0",
@@ -36450,6 +35952,7 @@
         "node-pre-gyp": {
           "version": "0.12.0",
           "bundled": true,
+          "dev": true,
           "optional": true,
           "requires": {
             "detect-libc": "^1.0.2",
@@ -36467,6 +35970,7 @@
         "nopt": {
           "version": "4.0.1",
           "bundled": true,
+          "dev": true,
           "optional": true,
           "requires": {
             "abbrev": "1",
@@ -36476,11 +35980,13 @@
         "npm-bundled": {
           "version": "1.0.6",
           "bundled": true,
+          "dev": true,
           "optional": true
         },
         "npm-packlist": {
           "version": "1.4.1",
           "bundled": true,
+          "dev": true,
           "optional": true,
           "requires": {
             "ignore-walk": "^3.0.1",
@@ -36490,6 +35996,7 @@
         "npmlog": {
           "version": "4.1.2",
           "bundled": true,
+          "dev": true,
           "optional": true,
           "requires": {
             "are-we-there-yet": "~1.1.2",
@@ -36501,16 +36008,19 @@
         "number-is-nan": {
           "version": "1.0.1",
           "bundled": true,
+          "dev": true,
           "optional": true
         },
         "object-assign": {
           "version": "4.1.1",
           "bundled": true,
+          "dev": true,
           "optional": true
         },
         "once": {
           "version": "1.4.0",
           "bundled": true,
+          "dev": true,
           "optional": true,
           "requires": {
             "wrappy": "1"
@@ -36519,16 +36029,19 @@
         "os-homedir": {
           "version": "1.0.2",
           "bundled": true,
+          "dev": true,
           "optional": true
         },
         "os-tmpdir": {
           "version": "1.0.2",
           "bundled": true,
+          "dev": true,
           "optional": true
         },
         "osenv": {
           "version": "0.1.5",
           "bundled": true,
+          "dev": true,
           "optional": true,
           "requires": {
             "os-homedir": "^1.0.0",
@@ -36538,16 +36051,19 @@
         "path-is-absolute": {
           "version": "1.0.1",
           "bundled": true,
+          "dev": true,
           "optional": true
         },
         "process-nextick-args": {
           "version": "2.0.0",
           "bundled": true,
+          "dev": true,
           "optional": true
         },
         "rc": {
           "version": "1.2.8",
           "bundled": true,
+          "dev": true,
           "optional": true,
           "requires": {
             "deep-extend": "^0.6.0",
@@ -36559,6 +36075,7 @@
             "minimist": {
               "version": "1.2.0",
               "bundled": true,
+              "dev": true,
               "optional": true
             }
           }
@@ -36566,6 +36083,7 @@
         "readable-stream": {
           "version": "2.3.6",
           "bundled": true,
+          "dev": true,
           "optional": true,
           "requires": {
             "core-util-is": "~1.0.0",
@@ -36580,6 +36098,7 @@
         "rimraf": {
           "version": "2.6.3",
           "bundled": true,
+          "dev": true,
           "optional": true,
           "requires": {
             "glob": "^7.1.3"
@@ -36588,36 +36107,43 @@
         "safe-buffer": {
           "version": "5.1.2",
           "bundled": true,
+          "dev": true,
           "optional": true
         },
         "safer-buffer": {
           "version": "2.1.2",
           "bundled": true,
+          "dev": true,
           "optional": true
         },
         "sax": {
           "version": "1.2.4",
           "bundled": true,
+          "dev": true,
           "optional": true
         },
         "semver": {
           "version": "5.7.0",
           "bundled": true,
+          "dev": true,
           "optional": true
         },
         "set-blocking": {
           "version": "2.0.0",
           "bundled": true,
+          "dev": true,
           "optional": true
         },
         "signal-exit": {
           "version": "3.0.2",
           "bundled": true,
+          "dev": true,
           "optional": true
         },
         "string_decoder": {
           "version": "1.1.1",
           "bundled": true,
+          "dev": true,
           "optional": true,
           "requires": {
             "safe-buffer": "~5.1.0"
@@ -36626,6 +36152,7 @@
         "string-width": {
           "version": "1.0.2",
           "bundled": true,
+          "dev": true,
           "optional": true,
           "requires": {
             "code-point-at": "^1.0.0",
@@ -36636,6 +36163,7 @@
         "strip-ansi": {
           "version": "3.0.1",
           "bundled": true,
+          "dev": true,
           "optional": true,
           "requires": {
             "ansi-regex": "^2.0.0"
@@ -36644,11 +36172,13 @@
         "strip-json-comments": {
           "version": "2.0.1",
           "bundled": true,
+          "dev": true,
           "optional": true
         },
         "tar": {
           "version": "4.4.8",
           "bundled": true,
+          "dev": true,
           "optional": true,
           "requires": {
             "chownr": "^1.1.1",
@@ -36663,11 +36193,13 @@
         "util-deprecate": {
           "version": "1.0.2",
           "bundled": true,
+          "dev": true,
           "optional": true
         },
         "wide-align": {
           "version": "1.1.3",
           "bundled": true,
+          "dev": true,
           "optional": true,
           "requires": {
             "string-width": "^1.0.2 || 2"
@@ -36676,11 +36208,13 @@
         "wrappy": {
           "version": "1.0.2",
           "bundled": true,
+          "dev": true,
           "optional": true
         },
         "yallist": {
           "version": "3.0.3",
           "bundled": true,
+          "dev": true,
           "optional": true
         }
       }
@@ -37127,15 +36661,6 @@
         "wbuf": "^1.1.0"
       }
     },
-    "html-element-map": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/html-element-map/-/html-element-map-1.1.0.tgz",
-      "integrity": "sha512-iqiG3dTZmy+uUaTmHarTL+3/A2VW9ox/9uasKEZC+R/wAtUrTcRlXPSaPqsnWPfIu8wqn09jQNwMRqzL54jSYA==",
-      "dev": true,
-      "requires": {
-        "array-filter": "^1.0.0"
-      }
-    },
     "html-encoding-sniffer": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz",
@@ -37156,33 +36681,6 @@
       "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
       "dev": true
     },
-    "htmlparser2": {
-      "version": "3.10.1",
-      "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz",
-      "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==",
-      "dev": true,
-      "requires": {
-        "domelementtype": "^1.3.1",
-        "domhandler": "^2.3.0",
-        "domutils": "^1.5.1",
-        "entities": "^1.1.1",
-        "inherits": "^2.0.1",
-        "readable-stream": "^3.1.1"
-      },
-      "dependencies": {
-        "readable-stream": {
-          "version": "3.4.0",
-          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz",
-          "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==",
-          "dev": true,
-          "requires": {
-            "inherits": "^2.0.3",
-            "string_decoder": "^1.1.1",
-            "util-deprecate": "^1.0.1"
-          }
-        }
-      }
-    },
     "http-deceiver": {
       "version": "1.2.7",
       "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz",
@@ -37917,8 +37415,7 @@
     "is-plain-obj": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
-      "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=",
-      "dev": true
+      "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg=="
     },
     "is-plain-object": {
       "version": "2.0.4",
@@ -37978,12 +37475,6 @@
         "has-tostringtag": "^1.0.0"
       }
     },
-    "is-subset": {
-      "version": "0.1.1",
-      "resolved": "https://registry.npmjs.org/is-subset/-/is-subset-0.1.1.tgz",
-      "integrity": "sha1-ilkRfZMt4d4A8kX83TnOQ/HpOaY=",
-      "dev": true
-    },
     "is-symbol": {
       "version": "1.0.4",
       "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz",
@@ -41219,15 +40710,6 @@
         "graceful-fs": "^4.2.4"
       }
     },
-    "jest-serializer-html": {
-      "version": "7.0.0",
-      "resolved": "https://registry.npmjs.org/jest-serializer-html/-/jest-serializer-html-7.0.0.tgz",
-      "integrity": "sha512-o3S2j/5yA9emV8+QRHqJ41SznW5cZ1PXIAk+aSToJffdhuaiSoDsa4IgqV8lNOHPp4cP0LNT7k5KjXjD+l6SGg==",
-      "dev": true,
-      "requires": {
-        "diffable-html": "^4.0.0"
-      }
-    },
     "jest-snapshot": {
       "version": "26.6.0",
       "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-26.6.0.tgz",
@@ -42672,24 +42154,12 @@
       "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz",
       "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ=="
     },
-    "lodash.escape": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-4.0.1.tgz",
-      "integrity": "sha1-yQRGkMIeBClL6qUXcS/e0fqI3pg=",
-      "dev": true
-    },
     "lodash.find": {
       "version": "4.6.0",
       "resolved": "https://registry.npmjs.org/lodash.find/-/lodash.find-4.6.0.tgz",
       "integrity": "sha1-ywcE1Hq3F4n/oN6Ll92Sb7iLE7E=",
       "dev": true
     },
-    "lodash.flattendeep": {
-      "version": "4.4.0",
-      "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz",
-      "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=",
-      "dev": true
-    },
     "lodash.get": {
       "version": "4.4.2",
       "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
@@ -42708,12 +42178,6 @@
       "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=",
       "dev": true
     },
-    "lodash.isequal": {
-      "version": "4.5.0",
-      "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
-      "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=",
-      "dev": true
-    },
     "lodash.isinteger": {
       "version": "4.0.4",
       "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
@@ -43351,12 +42815,6 @@
         "minimist": "^1.2.5"
       }
     },
-    "moo": {
-      "version": "0.4.3",
-      "resolved": "https://registry.npmjs.org/moo/-/moo-0.4.3.tgz",
-      "integrity": "sha512-gFD2xGCl8YFgGHsqJ9NKRVdwlioeW3mI1iqfLNYQOv0+6JRwG58Zk9DIGQgyIaffSYaO1xsKnMaYzzNr1KyIAw==",
-      "dev": true
-    },
     "mri": {
       "version": "1.1.4",
       "resolved": "https://registry.npmjs.org/mri/-/mri-1.1.4.tgz",
@@ -43414,33 +42872,6 @@
       "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
       "devOptional": true
     },
-    "nearley": {
-      "version": "2.19.0",
-      "resolved": "https://registry.npmjs.org/nearley/-/nearley-2.19.0.tgz",
-      "integrity": "sha512-2v52FTw7RPqieZr3Gth1luAXZR7Je6q3KaDHY5bjl/paDUdMu35fZ8ICNgiYJRr3tf3NMvIQQR1r27AvEr9CRA==",
-      "dev": true,
-      "requires": {
-        "commander": "^2.19.0",
-        "moo": "^0.4.3",
-        "railroad-diagrams": "^1.0.0",
-        "randexp": "0.4.6",
-        "semver": "^5.4.1"
-      },
-      "dependencies": {
-        "commander": {
-          "version": "2.20.3",
-          "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
-          "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
-          "dev": true
-        },
-        "semver": {
-          "version": "5.7.1",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
-          "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
-          "dev": true
-        }
-      }
-    },
     "negotiator": {
       "version": "0.6.3",
       "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
@@ -43587,15 +43018,6 @@
         "path-key": "^2.0.0"
       }
     },
-    "nth-check": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz",
-      "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==",
-      "dev": true,
-      "requires": {
-        "boolbase": "~1.0.0"
-      }
-    },
     "nwsapi": {
       "version": "2.2.0",
       "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz",
@@ -43650,16 +43072,6 @@
       "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==",
       "dev": true
     },
-    "object-is": {
-      "version": "1.1.5",
-      "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz",
-      "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==",
-      "dev": true,
-      "requires": {
-        "call-bind": "^1.0.2",
-        "define-properties": "^1.1.3"
-      }
-    },
     "object-keys": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
@@ -43718,18 +43130,6 @@
         "isobject": "^3.0.1"
       }
     },
-    "object.values": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.0.tgz",
-      "integrity": "sha512-8mf0nKLAoFX6VlNVdhGj31SVYpaNFtUnuoOXWyFEstsWRgU837AK+JYM0iAxwkSzGRbwn8cbFmgbyxj1j4VbXg==",
-      "dev": true,
-      "requires": {
-        "define-properties": "^1.1.3",
-        "es-abstract": "^1.12.0",
-        "function-bind": "^1.1.1",
-        "has": "^1.0.3"
-      }
-    },
     "obuf": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz",
@@ -44005,15 +43405,6 @@
       "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=",
       "dev": true
     },
-    "parse5": {
-      "version": "3.0.3",
-      "resolved": "https://registry.npmjs.org/parse5/-/parse5-3.0.3.tgz",
-      "integrity": "sha512-rgO9Zg5LLLkfJF9E6CCmXlSE4UVceloys8JrFqCcHloC3usd/kJCyPDwH2SOlzix2j3xaP9sUX3e8+kvkuleAA==",
-      "dev": true,
-      "requires": {
-        "@types/node": "*"
-      }
-    },
     "parseurl": {
       "version": "1.3.3",
       "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
@@ -44494,22 +43885,6 @@
         "performance-now": "^2.1.0"
       }
     },
-    "railroad-diagrams": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz",
-      "integrity": "sha1-635iZ1SN3t+4mcG5Dlc3RVnN234=",
-      "dev": true
-    },
-    "randexp": {
-      "version": "0.4.6",
-      "resolved": "https://registry.npmjs.org/randexp/-/randexp-0.4.6.tgz",
-      "integrity": "sha512-80WNmd9DA0tmZrw9qQa62GPPWfuXJknrmVmLcxvq4uZBdYqb1wYoKTmnlGUchvVWe0XiLupYkBoXVOxz3C8DYQ==",
-      "dev": true,
-      "requires": {
-        "discontinuous-range": "1.0.0",
-        "ret": "~0.1.10"
-      }
-    },
     "randombytes": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
@@ -45419,16 +44794,6 @@
         "glob": "^7.1.3"
       }
     },
-    "rst-selector-parser": {
-      "version": "2.2.3",
-      "resolved": "https://registry.npmjs.org/rst-selector-parser/-/rst-selector-parser-2.2.3.tgz",
-      "integrity": "sha1-gbIw6i/MYGbInjRy3nlChdmwPZE=",
-      "dev": true,
-      "requires": {
-        "lodash.flattendeep": "^4.4.0",
-        "nearley": "^2.7.10"
-      }
-    },
     "rsvp": {
       "version": "4.8.5",
       "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz",
@@ -46220,17 +45585,6 @@
         "side-channel": "^1.0.2"
       }
     },
-    "string.prototype.trim": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.0.tgz",
-      "integrity": "sha512-9EIjYD/WdlvLpn987+ctkLf0FfvBefOCuiEr2henD8X+7jfwPnyvTdmW8OJhj5p+M0/96mBdynLWkxUr+rHlpg==",
-      "dev": true,
-      "requires": {
-        "define-properties": "^1.1.3",
-        "es-abstract": "^1.13.0",
-        "function-bind": "^1.1.1"
-      }
-    },
     "string.prototype.trimend": {
       "version": "1.0.5",
       "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz",
diff --git a/package.json b/package.json
index db7e8821..f14b82ac 100644
--- a/package.json
+++ b/package.json
@@ -29,6 +29,7 @@
   },
   "dependencies": {
     "@tippyjs/react": "4.1.0",
+    "@types/react-test-renderer": "^17.0.0",
     "@vxna/mini-html-webpack-template": "^2.0.0",
     "acorn": "^6.4.1",
     "acorn-jsx": "^5.1.0",
@@ -44,6 +45,7 @@
     "doctrine": "^3.0.0",
     "es6-object-assign": "~1.1.0",
     "es6-promise": "^4.2.8",
+    "escape-string-regexp": "^1.0.5",
     "escodegen": "^1.12.0",
     "estree-walker": "~0.9.0",
     "fastest-levenshtein": "^1.0.9",
@@ -53,6 +55,7 @@
     "glob": "^7.1.5",
     "glogg": "^1.0.2",
     "hash-sum": "^2.0.0",
+    "is-plain-obj": "^1.1.0",
     "javascript-stringify": "^2.0.0",
     "jss": "^10.9.0",
     "jss-plugin-camel-case": "^10.9.0",
@@ -107,7 +110,6 @@
     "@types/buble": "^0.19.2",
     "@types/copy-webpack-plugin": "^5.0.2",
     "@types/doctrine": "0.0.3",
-    "@types/enzyme": "^3.10.3",
     "@types/escodegen": "0.0.6",
     "@types/estree": "^0.0.39",
     "@types/hash-sum": "^1.0.0",
@@ -126,19 +128,15 @@
     "@types/webpack-env": "^1.14.1",
     "@typescript-eslint/eslint-plugin": "^4.4.1",
     "@typescript-eslint/parser": "^4.4.1",
-    "@wojtekmaj/enzyme-adapter-react-17": "^0.6.7",
     "babel-core": "^7.0.0-bridge.0",
     "babel-eslint": "^10.1.0",
     "babel-jest": "^26.6.0",
     "babel-loader": "^8.1.0",
-    "cheerio": "^1.0.0-rc.3",
     "css-loader": "^6.7.1",
     "danger": "^10.5.3",
     "deabsdeep": "^1.0.6",
     "deepfreeze": "^2.0.0",
     "dog-names": "^2.0.0",
-    "enzyme": "^3.10.0",
-    "enzyme-to-json": "^3.4.3",
     "eslint": "^7.11.0",
     "eslint-config-tamia": "^7.2.6",
     "eslint-import-resolver-typescript": "^2.3.0",
@@ -150,7 +148,6 @@
     "fs-extra": "^9.0.0",
     "husky": "^4.3.0",
     "jest": "^26.6.0",
-    "jest-serializer-html": "^7.0.0",
     "keymirror": "^0.1.1",
     "lint-staged": "^10.5.1",
     "memfs": "~2.15.5",
@@ -219,9 +216,7 @@
       "<rootDir>/src/scripts/build.js"
     ],
     "snapshotSerializers": [
-      "deabsdeep/serializer",
-      "enzyme-to-json/serializer",
-      "jest-serializer-html"
+      "./test/deabsdeepSerializer"
     ]
   },
   "keywords": [
diff --git a/src/client/rsg-components/Argument/Argument.spec.tsx b/src/client/rsg-components/Argument/Argument.spec.tsx
index 80143bea..e2f9bd7c 100644
--- a/src/client/rsg-components/Argument/Argument.spec.tsx
+++ b/src/client/rsg-components/Argument/Argument.spec.tsx
@@ -1,9 +1,9 @@
 import React from 'react';
-import { shallow } from 'enzyme';
+import { createRenderer } from 'react-test-renderer/shallow';
 import { ArgumentRenderer, styles } from './ArgumentRenderer';
 
 const name = 'Foo';
-const type = {type: 'NameExpression', name: 'Array'};
+const type = { type: 'NameExpression', name: 'Array' };
 const description = 'Converts foo to bar';
 const props = {
 	classes: classes(styles),
@@ -11,73 +11,79 @@ const props = {
 };
 
 it('should render argument', () => {
-	const actual = shallow(
+	const renderer = createRenderer();
+	renderer.render(
 		<ArgumentRenderer {...props} name={name} type={type} description={description} />
 	);
 
-	expect(actual).toMatchSnapshot();
+	expect(renderer.getRenderOutput()).toMatchSnapshot();
 });
 
 it('should render argument without type', () => {
-	const actual = shallow(<ArgumentRenderer {...props} name={name} description={description} />);
+	const renderer = createRenderer();
+	renderer.render(<ArgumentRenderer {...props} name={name} description={description} />);
 
-	expect(actual).toMatchSnapshot();
+	expect(renderer.getRenderOutput()).toMatchSnapshot();
 });
 
 it('should render optional argument', () => {
-	const actual = shallow(
+	const renderer = createRenderer();
+	renderer.render(
 		<ArgumentRenderer
 			{...props}
-			type={{ type: 'OptionalType', expression: {type: 'NameExpression', name: 'Array'} }}
+			type={{ type: 'OptionalType', expression: { type: 'NameExpression', name: 'Array' } }}
 			description={description}
 		/>
 	);
 
-	expect(actual).toMatchSnapshot();
+	expect(renderer.getRenderOutput()).toMatchSnapshot();
 });
 
 it('should render default value of argument', () => {
-	const actual = shallow(
+	const renderer = createRenderer();
+	renderer.render(
 		<ArgumentRenderer
 			{...props}
-			type={{type: 'NameExpression', name: 'String'}}
+			type={{ type: 'NameExpression', name: 'String' }}
 			default="bar"
 			description={description}
 		/>
 	);
 
-	expect(actual).toMatchSnapshot();
+	expect(renderer.getRenderOutput()).toMatchSnapshot();
 });
 
 it('should render default value of optional argument', () => {
-	const actual = shallow(
+	const renderer = createRenderer();
+	renderer.render(
 		<ArgumentRenderer
 			{...props}
-			type={{ type: 'OptionalType', expression: {type: 'NameExpression', name: 'Boolean'} }}
+			type={{ type: 'OptionalType', expression: { type: 'NameExpression', name: 'Boolean' } }}
 			default="true"
 			description={description}
 		/>
 	);
 
-	expect(actual).toMatchSnapshot();
+	expect(renderer.getRenderOutput()).toMatchSnapshot();
 });
 
 it('should render argument without description', () => {
-	const actual = shallow(<ArgumentRenderer {...props} name={name} type={type} />);
+	const renderer = createRenderer();
+	renderer.render(<ArgumentRenderer {...props} name={name} type={type} />);
 
-	expect(actual).toMatchSnapshot();
+	expect(renderer.getRenderOutput()).toMatchSnapshot();
 });
 
 it('should render return value', () => {
-	const actual = shallow(
-		<ArgumentRenderer {...props} type={type} description={description} returns />
-	);
+	const renderer = createRenderer();
+	renderer.render(<ArgumentRenderer {...props} type={type} description={description} returns />);
 
-	expect(actual).toMatchSnapshot();
+	expect(renderer.getRenderOutput()).toMatchSnapshot();
 });
 
 it('should render with block styles', () => {
-	const actual = shallow(<ArgumentRenderer {...props} block />);
+	const renderer = createRenderer();
+	renderer.render(<ArgumentRenderer {...props} block />);
 
-	expect(actual).toMatchSnapshot();
+	expect(renderer.getRenderOutput()).toMatchSnapshot();
 });
diff --git a/src/client/rsg-components/Arguments/Arguments.spec.tsx b/src/client/rsg-components/Arguments/Arguments.spec.tsx
index 1cea174a..022c6d7b 100644
--- a/src/client/rsg-components/Arguments/Arguments.spec.tsx
+++ b/src/client/rsg-components/Arguments/Arguments.spec.tsx
@@ -1,5 +1,5 @@
 import React from 'react';
-import { shallow } from 'enzyme';
+import { createRenderer } from 'react-test-renderer/shallow';
 import { ArgumentsRenderer, styles } from './ArgumentsRenderer';
 
 const props = {
@@ -18,19 +18,22 @@ const args = [
 ];
 
 it('renderer should render arguments', () => {
-	const actual = shallow(<ArgumentsRenderer {...props} args={args} />);
+	const renderer = createRenderer();
+	renderer.render(<ArgumentsRenderer {...props} args={args} />);
 
-	expect(actual).toMatchSnapshot();
+	expect(renderer.getRenderOutput()).toMatchSnapshot();
 });
 
 it('renderer should render heading', () => {
-	const actual = shallow(<ArgumentsRenderer {...props} args={[args[1]]} heading />);
+	const renderer = createRenderer();
+	renderer.render(<ArgumentsRenderer {...props} args={[args[1]]} heading />);
 
-	expect(actual).toMatchSnapshot();
+	expect(renderer.getRenderOutput()).toMatchSnapshot();
 });
 
 it('renderer should render nothing for empty array', () => {
-	const actual = shallow(<ArgumentsRenderer {...props} args={[]} />);
+	const renderer = createRenderer();
+	renderer.render(<ArgumentsRenderer {...props} args={[]} />);
 
-	expect(actual.getElement()).toBe(null);
+	expect(renderer.getRenderOutput()).toBe(null);
 });
diff --git a/src/client/rsg-components/Arguments/__snapshots__/Arguments.spec.tsx.snap b/src/client/rsg-components/Arguments/__snapshots__/Arguments.spec.tsx.snap
index 4d84eaab..b928e58e 100644
--- a/src/client/rsg-components/Arguments/__snapshots__/Arguments.spec.tsx.snap
+++ b/src/client/rsg-components/Arguments/__snapshots__/Arguments.spec.tsx.snap
@@ -6,7 +6,6 @@ exports[`renderer should render arguments 1`] = `
 >
   <Styled(Argument)
     description="Converts foo to bar"
-    key="Foo"
     name="Foo"
     type={
       Object {
@@ -15,7 +14,6 @@ exports[`renderer should render arguments 1`] = `
     }
   />
   <Styled(Argument)
-    key="Foo"
     name="Foo"
   />
 </div>
@@ -35,7 +33,6 @@ exports[`renderer should render heading 1`] = `
     </Styled(Heading)>
   </div>
   <Styled(Argument)
-    key="Foo"
     name="Foo"
   />
 </div>
diff --git a/src/client/rsg-components/Code/Code.spec.tsx b/src/client/rsg-components/Code/Code.spec.tsx
index a9f2b440..20b54fde 100644
--- a/src/client/rsg-components/Code/Code.spec.tsx
+++ b/src/client/rsg-components/Code/Code.spec.tsx
@@ -1,12 +1,13 @@
 import React from 'react';
-import { shallow } from 'enzyme';
+import { createRenderer } from 'react-test-renderer/shallow';
 import { CodeRenderer } from './CodeRenderer';
 
 describe('Code blocks', () => {
 	it('should render code', () => {
 		const code = '<button>OK</button>';
-		const actual = shallow(<CodeRenderer classes={{}}>{code}</CodeRenderer>);
+		const renderer = createRenderer();
+		renderer.render(<CodeRenderer classes={{}}>{code}</CodeRenderer>);
 
-		expect(actual).toMatchSnapshot();
+		expect(renderer.getRenderOutput()).toMatchSnapshot();
 	});
 });
diff --git a/src/client/rsg-components/Components/Components.spec.tsx b/src/client/rsg-components/Components/Components.spec.tsx
index 2c63a514..a95969a4 100644
--- a/src/client/rsg-components/Components/Components.spec.tsx
+++ b/src/client/rsg-components/Components/Components.spec.tsx
@@ -1,5 +1,5 @@
 import React from 'react';
-import { shallow } from 'enzyme';
+import { createRenderer } from 'react-test-renderer/shallow';
 import ReactComponent from '../ReactComponent';
 import Components from './Components';
 import ComponentsRenderer from './ComponentsRenderer';
@@ -27,15 +27,17 @@ const components = [
 ];
 
 it('should render components list', () => {
-	const actual = shallow(
+	const renderer = createRenderer();
+	renderer.render(
 		<Components components={components} exampleMode={exampleMode} usageMode={usageMode} depth={3} />
 	);
 
-	expect(actual).toMatchSnapshot();
+	expect(renderer.getRenderOutput()).toMatchSnapshot();
 });
 
 it('renderer should render components list layout', () => {
-	const actual = shallow(
+	const renderer = createRenderer();
+	renderer.render(
 		<ComponentsRenderer>
 			<ReactComponent
 				key={0}
@@ -54,5 +56,5 @@ it('renderer should render components list layout', () => {
 		</ComponentsRenderer>
 	);
 
-	expect(actual).toMatchSnapshot();
+	expect(renderer.getRenderOutput()).toMatchSnapshot();
 });
diff --git a/src/client/rsg-components/Components/__snapshots__/Components.spec.tsx.snap b/src/client/rsg-components/Components/__snapshots__/Components.spec.tsx.snap
index a8af4686..b0bce5e9 100644
--- a/src/client/rsg-components/Components/__snapshots__/Components.spec.tsx.snap
+++ b/src/client/rsg-components/Components/__snapshots__/Components.spec.tsx.snap
@@ -15,7 +15,6 @@ exports[`renderer should render components list layout 1`] = `
     }
     depth={3}
     exampleMode="collapse"
-    key="0"
     usageMode="collapse"
   />
   <ReactComponent
@@ -31,7 +30,6 @@ exports[`renderer should render components list layout 1`] = `
     }
     depth={3}
     exampleMode="collapse"
-    key="1"
     usageMode="collapse"
   />
 </div>
@@ -52,7 +50,6 @@ exports[`should render components list 1`] = `
     }
     depth={3}
     exampleMode="collapse"
-    key="components/foo.js"
     usageMode="collapse"
   />
   <ReactComponent
@@ -68,7 +65,6 @@ exports[`should render components list 1`] = `
     }
     depth={3}
     exampleMode="collapse"
-    key="components/bar.js"
     usageMode="collapse"
   />
 </ComponentsRenderer>
diff --git a/src/client/rsg-components/ComponentsList/ComponentsList.spec.tsx b/src/client/rsg-components/ComponentsList/ComponentsList.spec.tsx
index 450a44c7..305aaa28 100644
--- a/src/client/rsg-components/ComponentsList/ComponentsList.spec.tsx
+++ b/src/client/rsg-components/ComponentsList/ComponentsList.spec.tsx
@@ -1,6 +1,6 @@
 /* eslint-disable compat/compat */
 import React from 'react';
-import { render } from '@testing-library/react';
+import { fireEvent, render } from '@testing-library/react';
 import ComponentsList from './ComponentsList';
 import Context from '../Context';
 
@@ -42,7 +42,7 @@ it('should ignore items without visibleName', () => {
 		</Provider>
 	);
 
-	expect(Array.from(getAllByRole('link')).map(node => (node as HTMLAnchorElement).href)).toEqual([
+	expect(Array.from(getAllByRole('link')).map((node) => (node as HTMLAnchorElement).href)).toEqual([
 		'http://localhost/#button',
 	]);
 });
@@ -71,10 +71,10 @@ it('should show content of items that are open and not what is closed', () => {
 		</Provider>
 	);
 
-	getByText('Button').click();
+	fireEvent.click(getByText('Button'));
 
 	expect(
-		Array.from(getAllByTestId('content')).map(node => (node as HTMLDivElement).innerHTML)
+		Array.from(getAllByTestId('content')).map((node) => (node as HTMLDivElement).innerHTML)
 	).toEqual(['Content for Button']);
 });
 
@@ -103,10 +103,10 @@ it('should show content of initialOpen items even if they are not active', () =>
 		</Provider>
 	);
 
-	getByText('Button').click();
+	fireEvent.click(getByText('Button'));
 
 	expect(
-		Array.from(getAllByTestId('content')).map(node => (node as HTMLDivElement).innerHTML)
+		Array.from(getAllByTestId('content')).map((node) => (node as HTMLDivElement).innerHTML)
 	).toEqual(['Content for Button', 'Content for Input']);
 });
 
@@ -137,9 +137,9 @@ it('should show content of forcedOpen items even if they are initially collapsed
 		</Provider>
 	);
 
-	getByText('Input').click();
+	fireEvent.click(getByText('Input'));
 
 	expect(
-		Array.from(getAllByTestId('content')).map(node => (node as HTMLDivElement).innerHTML)
+		Array.from(getAllByTestId('content')).map((node) => (node as HTMLDivElement).innerHTML)
 	).toEqual(['Content for Button', 'Content for Input']);
 });
diff --git a/src/client/rsg-components/Editor/Editor.spec.tsx b/src/client/rsg-components/Editor/Editor.spec.tsx
index 3f1c012d..6753ec62 100644
--- a/src/client/rsg-components/Editor/Editor.spec.tsx
+++ b/src/client/rsg-components/Editor/Editor.spec.tsx
@@ -1,6 +1,6 @@
 import React from 'react';
 import { fireEvent, render } from '@testing-library/react';
-import { shallow, mount } from 'enzyme';
+import { createRenderer } from 'react-test-renderer/shallow';
 import { Editor } from './Editor';
 
 const code = '<button>MyAwesomeCode</button>';
@@ -12,17 +12,18 @@ const props = {
 };
 describe('Editor', () => {
 	it('should renderer and editor', () => {
-		const actual = shallow(<Editor {...props} />);
+		const renderer = createRenderer();
+		renderer.render(<Editor {...props} />);
 
-		expect(actual).toMatchSnapshot();
+		expect(renderer.getRenderOutput()).toMatchSnapshot();
 	});
 
 	it('should update code', () => {
-		const actual = mount(<Editor {...props} />);
+		const { rerender, getByText } = render(<Editor {...props} />);
 
-		actual.setProps({ code: newCode });
+		rerender(<Editor {...props} code={newCode} />);
 
-		expect(actual.text()).toMatch(newCode);
+		expect(getByText(newCode));
 	});
 
 	it('should call onChange when textarea value changes', () => {
diff --git a/src/client/rsg-components/Editor/__snapshots__/Editor.spec.tsx.snap b/src/client/rsg-components/Editor/__snapshots__/Editor.spec.tsx.snap
index 15da31be..72a5c879 100644
--- a/src/client/rsg-components/Editor/__snapshots__/Editor.spec.tsx.snap
+++ b/src/client/rsg-components/Editor/__snapshots__/Editor.spec.tsx.snap
@@ -8,8 +8,6 @@ exports[`Editor should renderer and editor 1`] = `
   onValueChange={[Function]}
   padding={16}
   tabSize={2}
-  value=<button>
-  MyAwesomeCode
-</button>
+  value="<button>MyAwesomeCode</button>"
 />
 `;
diff --git a/src/client/rsg-components/Error/Error.spec.tsx b/src/client/rsg-components/Error/Error.spec.tsx
index a15f3ffd..e22fe647 100644
--- a/src/client/rsg-components/Error/Error.spec.tsx
+++ b/src/client/rsg-components/Error/Error.spec.tsx
@@ -1,11 +1,12 @@
 import React from 'react';
-import { shallow } from 'enzyme';
+import { createRenderer } from 'react-test-renderer/shallow';
 import { ErrorRenderer } from './ErrorRenderer';
 
 it('renderer should render error message', () => {
 	const error = { toString: () => 'error' };
 	const info = { componentStack: 'info' };
-	const actual = shallow(<ErrorRenderer classes={{}} error={error} info={info} />);
+	const renderer = createRenderer();
+	renderer.render(<ErrorRenderer classes={{}} error={error} info={info} />);
 
-	expect(actual).toMatchSnapshot();
+	expect(renderer.getRenderOutput()).toMatchSnapshot();
 });
diff --git a/src/client/rsg-components/Heading/Heading.spec.tsx b/src/client/rsg-components/Heading/Heading.spec.tsx
index 9a8481d3..832e0d71 100644
--- a/src/client/rsg-components/Heading/Heading.spec.tsx
+++ b/src/client/rsg-components/Heading/Heading.spec.tsx
@@ -1,20 +1,18 @@
 import React from 'react';
-import { html } from 'cheerio';
-import { render, shallow } from 'enzyme';
+import renderer from 'react-test-renderer';
 import Heading from './index';
 
 describe('Heading', () => {
 	it('should render a heading according to the level', () => {
-		let actual = shallow(<Heading level={3}>The heading</Heading>);
-		expect(actual.dive().name()).toBe('h3');
+		const actualH3 = renderer.create(<Heading level={3}>The heading</Heading>);
+		expect(actualH3.toJSON()).toMatchSnapshot();
 
-		actual = shallow(<Heading level={5}>The heading</Heading>);
-		expect(actual.dive().name()).toBe('h5');
+		const actualH5 = renderer.create(<Heading level={5}>The heading</Heading>);
+		expect(actualH5.toJSON()).toMatchSnapshot();
 	});
 
 	it('should render a heading', () => {
-		const actual = render(<Heading level={2}>The heading</Heading>);
-
-		expect(html(actual)).toMatchSnapshot();
+		const actual = renderer.create(<Heading level={2}>The heading</Heading>);
+		expect(actual.toJSON()).toMatchSnapshot();
 	});
 });
diff --git a/src/client/rsg-components/Heading/__snapshots__/Heading.spec.tsx.snap b/src/client/rsg-components/Heading/__snapshots__/Heading.spec.tsx.snap
index 0d150385..1d6fb2b3 100644
--- a/src/client/rsg-components/Heading/__snapshots__/Heading.spec.tsx.snap
+++ b/src/client/rsg-components/Heading/__snapshots__/Heading.spec.tsx.snap
@@ -1,7 +1,25 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
 exports[`Heading should render a heading 1`] = `
-<h2 class="rsg--heading-8 rsg--heading2-10">
+<h2
+  className="rsg--heading-0 rsg--heading2-2"
+>
   The heading
 </h2>
 `;
+
+exports[`Heading should render a heading according to the level 1`] = `
+<h3
+  className="rsg--heading-0 rsg--heading3-3"
+>
+  The heading
+</h3>
+`;
+
+exports[`Heading should render a heading according to the level 2`] = `
+<h5
+  className="rsg--heading-0 rsg--heading5-5"
+>
+  The heading
+</h5>
+`;
diff --git a/src/client/rsg-components/JsDoc/JsDoc.spec.tsx b/src/client/rsg-components/JsDoc/JsDoc.spec.tsx
index 7cafbe15..4ef4559b 100644
--- a/src/client/rsg-components/JsDoc/JsDoc.spec.tsx
+++ b/src/client/rsg-components/JsDoc/JsDoc.spec.tsx
@@ -1,5 +1,5 @@
 import React from 'react';
-import { shallow } from 'enzyme';
+import { createRenderer } from 'react-test-renderer/shallow';
 import JsDoc, { getMarkdown } from './JsDoc';
 
 const tags = {
@@ -73,14 +73,16 @@ describe('getMarkdown', () => {
 
 describe('JsDoc', () => {
 	it('should render Markdown', () => {
-		const actual = shallow(<JsDoc {...tags} />);
+		const renderer = createRenderer();
+		renderer.render(<JsDoc {...tags} />);
 
-		expect(actual).toMatchSnapshot();
+		expect(renderer.getRenderOutput()).toMatchSnapshot();
 	});
 
 	it('should render null for empty tags', () => {
-		const actual = shallow(<JsDoc />);
+		const renderer = createRenderer();
+		renderer.render(<JsDoc />);
 
-		expect(actual.getElement()).toBe(null);
+		expect(renderer.getRenderOutput()).toBe(null);
 	});
 });
diff --git a/src/client/rsg-components/Link/Link.spec.tsx b/src/client/rsg-components/Link/Link.spec.tsx
index be11b371..6168253a 100644
--- a/src/client/rsg-components/Link/Link.spec.tsx
+++ b/src/client/rsg-components/Link/Link.spec.tsx
@@ -1,36 +1,40 @@
+import { render } from '@testing-library/react';
 import React from 'react';
-import { shallow } from 'enzyme';
+import { createRenderer } from 'react-test-renderer/shallow';
 import { LinkRenderer } from './LinkRenderer';
 
 const href = '/foo';
 const children = 'Foo';
 
 it('renderer should render link', () => {
-	const actual = shallow(
+	const renderer = createRenderer();
+	renderer.render(
 		<LinkRenderer href={href} classes={{}}>
 			{children}
 		</LinkRenderer>
 	);
 
-	expect(actual).toMatchSnapshot();
+	expect(renderer.getRenderOutput()).toMatchSnapshot();
 });
 
 it('should compose passed class names', () => {
-	const actual = shallow(
+	const { getByRole } = render(
 		<LinkRenderer classes={{ link: 'baseLinkClass' }} href={href} className="customClass">
 			{children}
 		</LinkRenderer>
 	);
 
-	expect(actual.find('a').prop('className')).toBe('baseLinkClass customClass');
+	const a = getByRole('link');
+	expect(a.className).toBe('baseLinkClass customClass');
 });
 
 it('should properly pass the target attribute', () => {
-	const actual = shallow(
+	const { getByRole } = render(
 		<LinkRenderer href={href} target="_blank" classes={{}}>
 			{children}
 		</LinkRenderer>
 	);
 
-	expect(actual.find('a').prop('target')).toBe('_blank');
+	const a = getByRole('link');
+	expect(a.getAttribute('target')).toBe('_blank');
 });
diff --git a/src/client/rsg-components/Logo/Logo.spec.tsx b/src/client/rsg-components/Logo/Logo.spec.tsx
index ea4851ef..0f9e2bf0 100644
--- a/src/client/rsg-components/Logo/Logo.spec.tsx
+++ b/src/client/rsg-components/Logo/Logo.spec.tsx
@@ -1,9 +1,9 @@
 import React from 'react';
-import { render } from 'enzyme';
+import renderer from 'react-test-renderer';
 import LogoRenderer from './LogoRenderer';
 
 it('renderer should render header', () => {
-	const actual = render(<LogoRenderer>React Styleguidist</LogoRenderer>);
+	const actual = renderer.create(<LogoRenderer>React Styleguidist</LogoRenderer>);
 
-	expect(actual).toMatchSnapshot();
+	expect(actual.toJSON()).toMatchSnapshot();
 });
diff --git a/src/client/rsg-components/Logo/__snapshots__/Logo.spec.tsx.snap b/src/client/rsg-components/Logo/__snapshots__/Logo.spec.tsx.snap
index 2edde827..8642e57e 100644
--- a/src/client/rsg-components/Logo/__snapshots__/Logo.spec.tsx.snap
+++ b/src/client/rsg-components/Logo/__snapshots__/Logo.spec.tsx.snap
@@ -2,7 +2,7 @@
 
 exports[`renderer should render header 1`] = `
 <h1
-  class="rsg--logo-0"
+  className="rsg--logo-0"
 >
   React Styleguidist
 </h1>
diff --git a/src/client/rsg-components/Markdown/Blockquote/Blockquote.spec.tsx b/src/client/rsg-components/Markdown/Blockquote/Blockquote.spec.tsx
index 86acb1e3..dbf720b7 100644
--- a/src/client/rsg-components/Markdown/Blockquote/Blockquote.spec.tsx
+++ b/src/client/rsg-components/Markdown/Blockquote/Blockquote.spec.tsx
@@ -1,16 +1,18 @@
 import React from 'react';
-import { render } from 'enzyme';
+import renderer from 'react-test-renderer';
 import Blockquote from './index';
 
 describe('Markdown Blockquote', () => {
 	it('should render a blockquote', () => {
-		const actual = render(<Blockquote>To be, or not to be: that is the question</Blockquote>);
+		const actual = renderer.create(
+			<Blockquote>To be, or not to be: that is the question</Blockquote>
+		);
 
 		expect(actual).toMatchSnapshot();
 	});
 
 	it('should preserve custom css class', () => {
-		const actual = render(
+		const actual = renderer.create(
 			<Blockquote className="test-class">To be, or not to be: that is the question</Blockquote>
 		);
 
diff --git a/src/client/rsg-components/Markdown/Blockquote/__snapshots__/Blockquote.spec.tsx.snap b/src/client/rsg-components/Markdown/Blockquote/__snapshots__/Blockquote.spec.tsx.snap
index 8f33c167..7a57fbfa 100644
--- a/src/client/rsg-components/Markdown/Blockquote/__snapshots__/Blockquote.spec.tsx.snap
+++ b/src/client/rsg-components/Markdown/Blockquote/__snapshots__/Blockquote.spec.tsx.snap
@@ -2,7 +2,7 @@
 
 exports[`Markdown Blockquote should preserve custom css class 1`] = `
 <blockquote
-  class="rsg--blockquote-0 test-class"
+  className="rsg--blockquote-0 test-class"
 >
   To be, or not to be: that is the question
 </blockquote>
@@ -10,7 +10,7 @@ exports[`Markdown Blockquote should preserve custom css class 1`] = `
 
 exports[`Markdown Blockquote should render a blockquote 1`] = `
 <blockquote
-  class="rsg--blockquote-0"
+  className="rsg--blockquote-0"
 >
   To be, or not to be: that is the question
 </blockquote>
diff --git a/src/client/rsg-components/Markdown/Checkbox/Checkbox.spec.tsx b/src/client/rsg-components/Markdown/Checkbox/Checkbox.spec.tsx
index 400ee0d2..38fc3f9c 100644
--- a/src/client/rsg-components/Markdown/Checkbox/Checkbox.spec.tsx
+++ b/src/client/rsg-components/Markdown/Checkbox/Checkbox.spec.tsx
@@ -1,12 +1,12 @@
 import React from 'react';
-import { render } from 'enzyme';
+import renderer from 'react-test-renderer';
 
 import Checkbox from './index';
 
 describe('Markdown Checkbox', () => {
 	it('should render a checkbox input', () => {
-		const actual = render(<Checkbox />);
+		const actual = renderer.create(<Checkbox />);
 
-		expect(actual).toMatchSnapshot();
+		expect(actual.toJSON()).toMatchSnapshot();
 	});
 });
diff --git a/src/client/rsg-components/Markdown/Checkbox/__snapshots__/Checkbox.spec.tsx.snap b/src/client/rsg-components/Markdown/Checkbox/__snapshots__/Checkbox.spec.tsx.snap
index bb7123f3..f55599b0 100644
--- a/src/client/rsg-components/Markdown/Checkbox/__snapshots__/Checkbox.spec.tsx.snap
+++ b/src/client/rsg-components/Markdown/Checkbox/__snapshots__/Checkbox.spec.tsx.snap
@@ -2,7 +2,7 @@
 
 exports[`Markdown Checkbox should render a checkbox input 1`] = `
 <input
-  class="rsg--input-0"
+  className="rsg--input-0"
   type="checkbox"
 />
 `;
diff --git a/src/client/rsg-components/Markdown/Details/Details.spec.tsx b/src/client/rsg-components/Markdown/Details/Details.spec.tsx
index b064537f..c99ae4bd 100644
--- a/src/client/rsg-components/Markdown/Details/Details.spec.tsx
+++ b/src/client/rsg-components/Markdown/Details/Details.spec.tsx
@@ -1,17 +1,17 @@
 import React from 'react';
-import { render } from 'enzyme';
+import renderer from 'react-test-renderer';
 
 import { Details, DetailsSummary } from './index';
 
 describe('Markdown Details', () => {
 	it('should render a Details', () => {
-		const actual = render(
+		const actual = renderer.create(
 			<Details>
 				<DetailsSummary>Solution</DetailsSummary>
 				This is a hidden text.
 			</Details>
 		);
 
-		expect(actual).toMatchSnapshot();
+		expect(actual.toJSON()).toMatchSnapshot();
 	});
 });
diff --git a/src/client/rsg-components/Markdown/Details/__snapshots__/Details.spec.tsx.snap b/src/client/rsg-components/Markdown/Details/__snapshots__/Details.spec.tsx.snap
index 680ad27d..faed1627 100644
--- a/src/client/rsg-components/Markdown/Details/__snapshots__/Details.spec.tsx.snap
+++ b/src/client/rsg-components/Markdown/Details/__snapshots__/Details.spec.tsx.snap
@@ -2,10 +2,10 @@
 
 exports[`Markdown Details should render a Details 1`] = `
 <details
-  class="rsg--details-0"
+  className="rsg--details-0"
 >
   <summary
-    class="rsg--summary-2"
+    className="rsg--summary-2"
   >
     Solution
   </summary>
diff --git a/src/client/rsg-components/Markdown/Hr/Hr.spec.tsx b/src/client/rsg-components/Markdown/Hr/Hr.spec.tsx
index 58fd604f..d9098968 100644
--- a/src/client/rsg-components/Markdown/Hr/Hr.spec.tsx
+++ b/src/client/rsg-components/Markdown/Hr/Hr.spec.tsx
@@ -1,12 +1,12 @@
 import React from 'react';
-import { render } from 'enzyme';
+import renderer from 'react-test-renderer';
 
 import Hr from './index';
 
 describe('Markdown Hr', () => {
 	it('should render a horizontal rule', () => {
-		const actual = render(<Hr />);
+		const actual = renderer.create(<Hr />);
 
-		expect(actual).toMatchSnapshot();
+		expect(actual.toJSON()).toMatchSnapshot();
 	});
 });
diff --git a/src/client/rsg-components/Markdown/Hr/__snapshots__/Hr.spec.tsx.snap b/src/client/rsg-components/Markdown/Hr/__snapshots__/Hr.spec.tsx.snap
index aa6d63c1..ce5c66ff 100644
--- a/src/client/rsg-components/Markdown/Hr/__snapshots__/Hr.spec.tsx.snap
+++ b/src/client/rsg-components/Markdown/Hr/__snapshots__/Hr.spec.tsx.snap
@@ -2,6 +2,6 @@
 
 exports[`Markdown Hr should render a horizontal rule 1`] = `
 <hr
-  class="rsg--hr-0"
+  className="rsg--hr-0"
 />
 `;
diff --git a/src/client/rsg-components/Markdown/List/List.spec.tsx b/src/client/rsg-components/Markdown/List/List.spec.tsx
index 52da543a..e2280bcc 100644
--- a/src/client/rsg-components/Markdown/List/List.spec.tsx
+++ b/src/client/rsg-components/Markdown/List/List.spec.tsx
@@ -1,28 +1,28 @@
 import React from 'react';
-import { render } from 'enzyme';
+import renderer from 'react-test-renderer';
 
 import List from './index';
 
 describe('Markdown List', () => {
 	it('should render an unordered list', () => {
-		const actual = render(
+		const actual = renderer.create(
 			<List>
 				<li>First</li>
 				<li>Second</li>
 			</List>
 		);
 
-		expect(actual).toMatchSnapshot();
+		expect(actual.toJSON()).toMatchSnapshot();
 	});
 
 	it('should render an ordered list', () => {
-		const actual = render(
+		const actual = renderer.create(
 			<List ordered>
 				<li>First</li>
 				<li>Second</li>
 			</List>
 		);
 
-		expect(actual).toMatchSnapshot();
+		expect(actual.toJSON()).toMatchSnapshot();
 	});
 });
diff --git a/src/client/rsg-components/Markdown/List/__snapshots__/List.spec.tsx.snap b/src/client/rsg-components/Markdown/List/__snapshots__/List.spec.tsx.snap
index 2151e999..19d25070 100644
--- a/src/client/rsg-components/Markdown/List/__snapshots__/List.spec.tsx.snap
+++ b/src/client/rsg-components/Markdown/List/__snapshots__/List.spec.tsx.snap
@@ -2,15 +2,15 @@
 
 exports[`Markdown List should render an ordered list 1`] = `
 <ol
-  class="rsg--list-0 rsg--ordered-1"
+  className="rsg--list-0 rsg--ordered-1"
 >
   <li
-    class="rsg--li-2"
+    className="rsg--li-2"
   >
     First
   </li>
   <li
-    class="rsg--li-2"
+    className="rsg--li-2"
   >
     Second
   </li>
@@ -19,15 +19,15 @@ exports[`Markdown List should render an ordered list 1`] = `
 
 exports[`Markdown List should render an unordered list 1`] = `
 <ul
-  class="rsg--list-0"
+  className="rsg--list-0"
 >
   <li
-    class="rsg--li-2"
+    className="rsg--li-2"
   >
     First
   </li>
   <li
-    class="rsg--li-2"
+    className="rsg--li-2"
   >
     Second
   </li>
diff --git a/src/client/rsg-components/Markdown/Markdown.spec.tsx b/src/client/rsg-components/Markdown/Markdown.spec.tsx
index 635f0def..16eddfd5 100644
--- a/src/client/rsg-components/Markdown/Markdown.spec.tsx
+++ b/src/client/rsg-components/Markdown/Markdown.spec.tsx
@@ -1,23 +1,23 @@
+import { render } from '@testing-library/react';
 import React from 'react';
-import { html } from 'cheerio';
-import { render, mount } from 'enzyme';
+import renderer from 'react-test-renderer';
 import Markdown from './Markdown';
 
 describe('Markdown', () => {
 	const expectSnapshotToMatch = (markdown: string) => {
-		const actual = render(<Markdown text={markdown} />);
+		const actual = renderer.create(<Markdown text={markdown} />);
 
-		expect(html(actual)).toMatchSnapshot();
+		expect(actual.toJSON()).toMatchSnapshot();
 	};
 
 	it('should forward DOM attributes onto resulting HTML', () => {
 		const markdown =
 			'<a href="test.com" id="preserve-my-id" class="preserve-my-class">Something</a>';
 
-		const actual = mount(<Markdown text={markdown} />);
+		const { getByRole } = render(<Markdown text={markdown} />);
 
-		expect(actual.find('a').props().id).toEqual('preserve-my-id');
-		expect(actual.find('a').props().className).toContain('preserve-my-class');
+		expect(getByRole('link').getAttribute('id')).toEqual('preserve-my-id');
+		expect(getByRole('link').className).toContain('preserve-my-class');
 	});
 
 	it('should render links', () => {
@@ -125,40 +125,38 @@ and this is _emphasized_
 `);
 	});
 
-	it('should ignore single line comments', () => {
+	it.only('should ignore single line comments', () => {
 		const markdown = `Hello World
 <!-- This is a single line comment -->
 `;
-		const actual = mount(<Markdown text={markdown} />);
-		const pChildren = actual.find('p').props().children as string[];
+		const { queryByText } = render(<Markdown text={markdown} />);
 
-		expect(pChildren[0]).not.toContain('This is a single line comment');
+		expect(queryByText('This is a single line comment')).toBe(null);
 	});
 
 	it('should ignore multiline comments', () => {
 		const markdown = `Hello World
 <!--
-This is a 
+This is a
 multiline
 comment
 -->
 `;
-		const actual = mount(<Markdown text={markdown} />);
-		const pChildren = actual.find('p').props().children as string[];
+		const { queryByText } = render(<Markdown text={markdown} />);
 
-		expect(pChildren[0]).not.toContain(
-			`This is a 
+		expect(
+			queryByText(`This is a
 multiline
-comment`
-		);
+comment`)
+		).toBe(null);
 	});
 });
 
 describe('Markdown inline', () => {
 	const expectSnapshotToMatch = (markdown: string) => {
-		const actual = render(<Markdown text={markdown} inline />);
+		const actual = renderer.create(<Markdown text={markdown} inline />);
 
-		expect(html(actual)).toMatchSnapshot();
+		expect(actual).toMatchSnapshot();
 	};
 
 	it('should render text in a span', () => {
diff --git a/src/client/rsg-components/Markdown/MarkdownHeading/MarkdownHeading.spec.tsx b/src/client/rsg-components/Markdown/MarkdownHeading/MarkdownHeading.spec.tsx
index 3aa2543c..9e3363f7 100644
--- a/src/client/rsg-components/Markdown/MarkdownHeading/MarkdownHeading.spec.tsx
+++ b/src/client/rsg-components/Markdown/MarkdownHeading/MarkdownHeading.spec.tsx
@@ -1,16 +1,15 @@
 import React from 'react';
-import { html } from 'cheerio';
-import { render } from 'enzyme';
+import renderer from 'react-test-renderer';
 import MarkdownHeading from './index';
 
 describe('Markdown Heading', () => {
 	it('should render a heading with a wrapper that provides margin and an id', () => {
-		const actual = render(
+		const actual = renderer.create(
 			<MarkdownHeading id="the-markdown-heading" level={2}>
 				The markdown heading
 			</MarkdownHeading>
 		);
 
-		expect(html(actual)).toMatchSnapshot();
+		expect(actual).toMatchSnapshot();
 	});
 });
diff --git a/src/client/rsg-components/Markdown/MarkdownHeading/__snapshots__/MarkdownHeading.spec.tsx.snap b/src/client/rsg-components/Markdown/MarkdownHeading/__snapshots__/MarkdownHeading.spec.tsx.snap
index 2ff8c068..423ecbcc 100644
--- a/src/client/rsg-components/Markdown/MarkdownHeading/__snapshots__/MarkdownHeading.spec.tsx.snap
+++ b/src/client/rsg-components/Markdown/MarkdownHeading/__snapshots__/MarkdownHeading.spec.tsx.snap
@@ -1,9 +1,12 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
 exports[`Markdown Heading should render a heading with a wrapper that provides margin and an id 1`] = `
-<div class="rsg--spacing-0">
-  <h2 id="the-markdown-heading"
-      class="rsg--heading-2 rsg--heading2-4"
+<div
+  className="rsg--spacing-0"
+>
+  <h2
+    className="rsg--heading-2 rsg--heading2-4"
+    id="the-markdown-heading"
   >
     The markdown heading
   </h2>
diff --git a/src/client/rsg-components/Markdown/Pre/Pre.spec.tsx b/src/client/rsg-components/Markdown/Pre/Pre.spec.tsx
index d715e068..cbb309ae 100644
--- a/src/client/rsg-components/Markdown/Pre/Pre.spec.tsx
+++ b/src/client/rsg-components/Markdown/Pre/Pre.spec.tsx
@@ -1,19 +1,19 @@
 import React from 'react';
-import { render } from 'enzyme';
+import renderer from 'react-test-renderer';
 
 import Pre from './index';
 
 describe('Markdown Pre', () => {
 	it('should render a pre', () => {
-		const actual = render(<Pre>This is pre-formatted text.</Pre>);
+		const actual = renderer.create(<Pre>This is pre-formatted text.</Pre>);
 
-		expect(actual).toMatchSnapshot();
+		expect(actual.toJSON()).toMatchSnapshot();
 	});
 
 	it('should render highlighted code', () => {
 		const code = '<button>OK</button>';
-		const actual = render(<Pre className="lang-html">{code}</Pre>);
+		const actual = renderer.create(<Pre className="lang-html">{code}</Pre>);
 
-		expect(actual).toMatchSnapshot();
+		expect(actual.toJSON()).toMatchSnapshot();
 	});
 });
diff --git a/src/client/rsg-components/Markdown/Pre/__snapshots__/Pre.spec.tsx.snap b/src/client/rsg-components/Markdown/Pre/__snapshots__/Pre.spec.tsx.snap
index d90978ba..f18486f3 100644
--- a/src/client/rsg-components/Markdown/Pre/__snapshots__/Pre.spec.tsx.snap
+++ b/src/client/rsg-components/Markdown/Pre/__snapshots__/Pre.spec.tsx.snap
@@ -2,7 +2,7 @@
 
 exports[`Markdown Pre should render a pre 1`] = `
 <pre
-  class="rsg--pre-0"
+  className="rsg--pre-0"
 >
   This is pre-formatted text.
 </pre>
@@ -10,10 +10,11 @@ exports[`Markdown Pre should render a pre 1`] = `
 
 exports[`Markdown Pre should render highlighted code 1`] = `
 <pre
-  class="lang-html rsg--pre-0"
->
-  <button>
-    OK
-  </button>
-</pre>
+  className="lang-html rsg--pre-0"
+  dangerouslySetInnerHTML={
+    Object {
+      "__html": "<button>OK</button>",
+    }
+  }
+/>
 `;
diff --git a/src/client/rsg-components/Markdown/Table/Table.spec.tsx b/src/client/rsg-components/Markdown/Table/Table.spec.tsx
index 66991415..2cc49bd4 100644
--- a/src/client/rsg-components/Markdown/Table/Table.spec.tsx
+++ b/src/client/rsg-components/Markdown/Table/Table.spec.tsx
@@ -1,11 +1,11 @@
 import React from 'react';
-import { render } from 'enzyme';
+import renderer from 'react-test-renderer';
 
 import { Table, TableHead, TableBody, TableRow, TableCell } from './index';
 
 describe('Markdown Table', () => {
 	it('should render a table', () => {
-		const actual = render(
+		const actual = renderer.create(
 			<Table>
 				<TableHead>
 					<TableRow>
@@ -22,6 +22,6 @@ describe('Markdown Table', () => {
 			</Table>
 		);
 
-		expect(actual).toMatchSnapshot();
+		expect(actual.toJSON()).toMatchSnapshot();
 	});
 });
diff --git a/src/client/rsg-components/Markdown/Table/__snapshots__/Table.spec.tsx.snap b/src/client/rsg-components/Markdown/Table/__snapshots__/Table.spec.tsx.snap
index 0a4869df..5fb7ce03 100644
--- a/src/client/rsg-components/Markdown/Table/__snapshots__/Table.spec.tsx.snap
+++ b/src/client/rsg-components/Markdown/Table/__snapshots__/Table.spec.tsx.snap
@@ -2,19 +2,19 @@
 
 exports[`Markdown Table should render a table 1`] = `
 <table
-  class="rsg--table-0"
+  className="rsg--table-0"
 >
   <thead
-    class="rsg--thead-2"
+    className="rsg--thead-2"
   >
     <tr>
       <th
-        class="rsg--th-4 rsg--td-3"
+        className="rsg--th-4 rsg--td-3"
       >
         1st header
       </th>
       <th
-        class="rsg--th-4 rsg--td-3"
+        className="rsg--th-4 rsg--td-3"
       >
         2nd header
       </th>
@@ -23,12 +23,12 @@ exports[`Markdown Table should render a table 1`] = `
   <tbody>
     <tr>
       <td
-        class="rsg--td-3"
+        className="rsg--td-3"
       >
         1st cell
       </td>
       <td
-        class="rsg--td-3"
+        className="rsg--td-3"
       >
         2nd cell
       </td>
diff --git a/src/client/rsg-components/Markdown/__snapshots__/Markdown.spec.tsx.snap b/src/client/rsg-components/Markdown/__snapshots__/Markdown.spec.tsx.snap
index 427bbf0b..d351033f 100644
--- a/src/client/rsg-components/Markdown/__snapshots__/Markdown.spec.tsx.snap
+++ b/src/client/rsg-components/Markdown/__snapshots__/Markdown.spec.tsx.snap
@@ -1,48 +1,48 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
 exports[`Markdown inline should render text in a span 1`] = `
-<span class="rsg--text-11 rsg--inheritSize-12 rsg--baseColor-16">
+<span className="rsg--text-11 rsg--inheritSize-12 rsg--baseColor-16">
   Hello world!
 </span>
 `;
 
 exports[`Markdown should render a blockquote 1`] = `
-<blockquote class="rsg--blockquote-25">
-  <p class="rsg--para-2">
+<blockquote className="rsg--blockquote-25">
+  <p className="rsg--para-2">
     This is a blockquote.
 And this is a second line.
   </p>
 </blockquote>
 `;
 
-exports[`Markdown should render a horizontal rule 1`] = `<hr class="rsg--hr-28">`;
+exports[`Markdown should render a horizontal rule 1`] = `<hr className="rsg--hr-28">`;
 
 exports[`Markdown should render a table 1`] = `
-<table class="rsg--table-29">
-  <thead class="rsg--thead-30">
+<table className="rsg--table-29">
+  <thead className="rsg--thead-30">
     <tr>
-      <th class="rsg--th-32 rsg--td-31">
+      <th className="rsg--th-32 rsg--td-31">
         heading 1
       </th>
-      <th class="rsg--th-32 rsg--td-31">
+      <th className="rsg--th-32 rsg--td-31">
         heading 2
       </th>
     </tr>
   </thead>
   <tbody>
     <tr>
-      <td class="rsg--td-31">
+      <td className="rsg--td-31">
         foo
       </td>
-      <td class="rsg--td-31">
+      <td className="rsg--td-31">
         bar
       </td>
     </tr>
     <tr>
-      <td class="rsg--td-31">
+      <td className="rsg--td-31">
         more foo
       </td>
-      <td class="rsg--td-31">
+      <td className="rsg--td-31">
         more bar
       </td>
     </tr>
@@ -51,26 +51,26 @@ exports[`Markdown should render a table 1`] = `
 `;
 
 exports[`Markdown should render check-lists 1`] = `
-<ul class="rsg--list-21">
-  <li class="rsg--li-23">
+<ul className="rsg--list-21">
+  <li className="rsg--li-23">
     <input type="checkbox"
            readonly
-           class="rsg--input-24"
+           className="rsg--input-24"
     >
     to do 1
   </li>
-  <li class="rsg--li-23">
+  <li className="rsg--li-23">
     <input type="checkbox"
            readonly
-           class="rsg--input-24"
+           className="rsg--input-24"
     >
     to do 2
   </li>
-  <li class="rsg--li-23">
+  <li className="rsg--li-23">
     <input type="checkbox"
            checked
            readonly
-           class="rsg--input-24"
+           className="rsg--input-24"
     >
     to do 3
   </li>
@@ -78,7 +78,7 @@ exports[`Markdown should render check-lists 1`] = `
 `;
 
 exports[`Markdown should render code blocks without escaping 1`] = `
-<pre class="lang-html rsg--pre-26">
+<pre className="lang-html rsg--pre-26">
   <foo>
   </foo>
 </pre>
@@ -86,15 +86,15 @@ exports[`Markdown should render code blocks without escaping 1`] = `
 
 exports[`Markdown should render emphasis and strong text 1`] = `
 <div>
-  <p class="rsg--para-2">
+  <p className="rsg--para-2">
     this text is
-    <strong class="rsg--text-11 rsg--inheritSize-12 rsg--baseColor-16 rsg--strong-19">
+    <strong className="rsg--text-11 rsg--inheritSize-12 rsg--baseColor-16 rsg--strong-19">
       strong
     </strong>
   </p>
-  <p class="rsg--para-2">
+  <p className="rsg--para-2">
     and this is
-    <em class="rsg--text-11 rsg--inheritSize-12 rsg--baseColor-16 rsg--em-18">
+    <em className="rsg--text-11 rsg--inheritSize-12 rsg--baseColor-16 rsg--em-18">
       emphasized
     </em>
   </p>
@@ -103,44 +103,44 @@ exports[`Markdown should render emphasis and strong text 1`] = `
 
 exports[`Markdown should render headings with generated ids 1`] = `
 <div>
-  <div class="rsg--spacing-3">
+  <div className="rsg--spacing-3">
     <h1 id="one"
-        class="rsg--heading-4 rsg--heading1-5"
+        className="rsg--heading-4 rsg--heading1-5"
     >
       one
     </h1>
   </div>
-  <div class="rsg--spacing-3">
+  <div className="rsg--spacing-3">
     <h2 id="two"
-        class="rsg--heading-4 rsg--heading2-6"
+        className="rsg--heading-4 rsg--heading2-6"
     >
       two
     </h2>
   </div>
-  <div class="rsg--spacing-3">
+  <div className="rsg--spacing-3">
     <h3 id="three"
-        class="rsg--heading-4 rsg--heading3-7"
+        className="rsg--heading-4 rsg--heading3-7"
     >
       three
     </h3>
   </div>
-  <div class="rsg--spacing-3">
+  <div className="rsg--spacing-3">
     <h4 id="four"
-        class="rsg--heading-4 rsg--heading4-8"
+        className="rsg--heading-4 rsg--heading4-8"
     >
       four
     </h4>
   </div>
-  <div class="rsg--spacing-3">
+  <div className="rsg--spacing-3">
     <h5 id="five"
-        class="rsg--heading-4 rsg--heading5-9"
+        className="rsg--heading-4 rsg--heading5-9"
     >
       five
     </h5>
   </div>
-  <div class="rsg--spacing-3">
+  <div className="rsg--spacing-3">
     <h6 id="six"
-        class="rsg--heading-4 rsg--heading6-10"
+        className="rsg--heading-4 rsg--heading6-10"
     >
       six
     </h6>
@@ -149,9 +149,9 @@ exports[`Markdown should render headings with generated ids 1`] = `
 `;
 
 exports[`Markdown should render inline code with escaping 1`] = `
-<p class="rsg--para-2">
+<p className="rsg--para-2">
   Foo
-  <code class="rsg--code-27">
+  <code className="rsg--code-27">
     &lt;bar&gt;
   </code>
   baz
@@ -159,10 +159,10 @@ exports[`Markdown should render inline code with escaping 1`] = `
 `;
 
 exports[`Markdown should render links 1`] = `
-<p class="rsg--para-2">
+<p className="rsg--para-2">
   a
   <a href="http://test.com"
-     class="rsg--link-0"
+     className="rsg--link-0"
   >
     link
   </a>
@@ -170,39 +170,39 @@ exports[`Markdown should render links 1`] = `
 `;
 
 exports[`Markdown should render mixed nested lists 1`] = `
-<ul class="rsg--list-21">
-  <li class="rsg--li-23">
+<ul className="rsg--list-21">
+  <li className="rsg--li-23">
     list 1
   </li>
-  <li class="rsg--li-23">
+  <li className="rsg--li-23">
     list 2
-    <ol class="rsg--list-21 rsg--ordered-22">
-      <li class="rsg--li-23">
+    <ol className="rsg--list-21 rsg--ordered-22">
+      <li className="rsg--li-23">
         Sub-list
       </li>
-      <li class="rsg--li-23">
+      <li className="rsg--li-23">
         Sub-list
       </li>
-      <li class="rsg--li-23">
+      <li className="rsg--li-23">
         Sub-list
       </li>
     </ol>
   </li>
-  <li class="rsg--li-23">
+  <li className="rsg--li-23">
     list 3
   </li>
 </ul>
 `;
 
 exports[`Markdown should render ordered lists 1`] = `
-<ol class="rsg--list-21 rsg--ordered-22">
-  <li class="rsg--li-23">
+<ol className="rsg--list-21 rsg--ordered-22">
+  <li className="rsg--li-23">
     list
   </li>
-  <li class="rsg--li-23">
+  <li className="rsg--li-23">
     item
   </li>
-  <li class="rsg--li-23">
+  <li className="rsg--li-23">
     three
   </li>
 </ol>
@@ -210,31 +210,31 @@ exports[`Markdown should render ordered lists 1`] = `
 
 exports[`Markdown should render paragraphs 1`] = `
 <div>
-  <p class="rsg--para-2">
+  <p className="rsg--para-2">
     a paragraph
   </p>
-  <p class="rsg--para-2">
+  <p className="rsg--para-2">
     another paragraph
   </p>
 </div>
 `;
 
 exports[`Markdown should render pre-formatted text 1`] = `
-<pre class="rsg--pre-26">
+<pre className="rsg--pre-26">
   this is preformatted
 so is this
 </pre>
 `;
 
 exports[`Markdown should render unordered lists 1`] = `
-<ul class="rsg--list-21">
-  <li class="rsg--li-23">
+<ul className="rsg--list-21">
+  <li className="rsg--li-23">
     list
   </li>
-  <li class="rsg--li-23">
+  <li className="rsg--li-23">
     item
   </li>
-  <li class="rsg--li-23">
+  <li className="rsg--li-23">
     three
   </li>
 </ul>
diff --git a/src/client/rsg-components/Message/Message.spec.tsx b/src/client/rsg-components/Message/Message.spec.tsx
index a19006ca..5e44b5cb 100644
--- a/src/client/rsg-components/Message/Message.spec.tsx
+++ b/src/client/rsg-components/Message/Message.spec.tsx
@@ -1,17 +1,19 @@
 import React from 'react';
-import { shallow } from 'enzyme';
+import { createRenderer } from 'react-test-renderer/shallow';
 import { MessageRenderer } from './MessageRenderer';
 
 it('renderer should render message', () => {
 	const message = 'Hello *world*!';
-	const actual = shallow(<MessageRenderer classes={{}}>{message}</MessageRenderer>);
+	const renderer = createRenderer();
+	renderer.render(<MessageRenderer classes={{}}>{message}</MessageRenderer>);
 
-	expect(actual).toMatchSnapshot();
+	expect(renderer.getRenderOutput()).toMatchSnapshot();
 });
 
 it('renderer should render message for array', () => {
 	const messages = ['Hello *world*!', 'Foo _bar_'];
-	const actual = shallow(<MessageRenderer classes={{}}>{messages}</MessageRenderer>);
+	const renderer = createRenderer();
+	renderer.render(<MessageRenderer classes={{}}>{messages}</MessageRenderer>);
 
-	expect(actual).toMatchSnapshot();
+	expect(renderer.getRenderOutput()).toMatchSnapshot();
 });
diff --git a/src/client/rsg-components/Methods/Methods.spec.tsx b/src/client/rsg-components/Methods/Methods.spec.tsx
index 3e81957b..df031981 100644
--- a/src/client/rsg-components/Methods/Methods.spec.tsx
+++ b/src/client/rsg-components/Methods/Methods.spec.tsx
@@ -1,7 +1,7 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import { parse, MethodDescriptor } from 'react-docgen';
-import { shallow } from 'enzyme';
+import { createRenderer } from 'react-test-renderer/shallow';
 import MethodsRenderer, { columns } from './MethodsRenderer';
 
 // Test renderers with clean readable snapshot diffs
@@ -37,15 +37,19 @@ function render(methods: string[]) {
 		undefined,
 		{ filename: '' }
 	);
+	const renderer = createRenderer();
 	if (Array.isArray(parsed) || !parsed.methods) {
-		return shallow(<div />);
+		renderer.render(<div />);
+	} else {
+		renderer.render(<ColumnsRenderer methods={parsed.methods} />);
 	}
-	return shallow(<ColumnsRenderer methods={parsed.methods} />);
+	return renderer.getRenderOutput();
 }
 
 describe('MethodsRenderer', () => {
 	it('should render a table', () => {
-		const actual = shallow(
+		const renderer = createRenderer();
+		renderer.render(
 			<MethodsRenderer
 				methods={[
 					{
@@ -58,7 +62,7 @@ describe('MethodsRenderer', () => {
 			/>
 		);
 
-		expect(actual).toMatchSnapshot();
+		expect(renderer.getRenderOutput()).toMatchSnapshot();
 	});
 });
 
@@ -86,7 +90,8 @@ describe('PropsRenderer', () => {
 	});
 
 	it('should render JsDoc tags', () => {
-		const actual = shallow(
+		const renderer = createRenderer();
+		renderer.render(
 			<ColumnsRenderer
 				methods={[
 					{
@@ -104,11 +109,12 @@ describe('PropsRenderer', () => {
 			/>
 		);
 
-		expect(actual).toMatchSnapshot();
+		expect(renderer.getRenderOutput()).toMatchSnapshot();
 	});
 
 	it('should render deprecated JsDoc tags', () => {
-		const actual = shallow(
+		const renderer = createRenderer();
+		renderer.render(
 			<ColumnsRenderer
 				methods={[
 					{
@@ -126,6 +132,6 @@ describe('PropsRenderer', () => {
 			/>
 		);
 
-		expect(actual).toMatchSnapshot();
+		expect(renderer.getRenderOutput()).toMatchSnapshot();
 	});
 });
diff --git a/src/client/rsg-components/Methods/__snapshots__/Methods.spec.tsx.snap b/src/client/rsg-components/Methods/__snapshots__/Methods.spec.tsx.snap
index 280cdd37..b703801a 100644
--- a/src/client/rsg-components/Methods/__snapshots__/Methods.spec.tsx.snap
+++ b/src/client/rsg-components/Methods/__snapshots__/Methods.spec.tsx.snap
@@ -34,28 +34,20 @@ exports[`MethodsRenderer should render a table 1`] = `
 
 exports[`PropsRenderer should render JsDoc tags 1`] = `
 <ul>
-  <li
-    key="0"
-  >
-    <div
-      key="0"
-    >
+  <li>
+    <div>
       <Styled(Name)
         deprecated={false}
       >
         Foo()
       </Styled(Name)>
     </div>
-    <div
-      key="1"
-    >
+    <div>
       <Styled(Arguments)
         args={Array []}
       />
     </div>
-    <div
-      key="2"
-    >
+    <div>
       <div>
         <JsDoc
           since={
@@ -75,28 +67,20 @@ exports[`PropsRenderer should render JsDoc tags 1`] = `
 
 exports[`PropsRenderer should render deprecated JsDoc tags 1`] = `
 <ul>
-  <li
-    key="0"
-  >
-    <div
-      key="0"
-    >
+  <li>
+    <div>
       <Styled(Name)
         deprecated={true}
       >
         Foo()
       </Styled(Name)>
     </div>
-    <div
-      key="1"
-    >
+    <div>
       <Styled(Arguments)
         args={Array []}
       />
     </div>
-    <div
-      key="2"
-    >
+    <div>
       <div>
         <JsDoc
           deprecated={
@@ -116,21 +100,15 @@ exports[`PropsRenderer should render deprecated JsDoc tags 1`] = `
 
 exports[`PropsRenderer should render parameters 1`] = `
 <ul>
-  <li
-    key="0"
-  >
-    <div
-      key="0"
-    >
+  <li>
+    <div>
       <Styled(Name)
         deprecated={false}
       >
         method()
       </Styled(Name)>
     </div>
-    <div
-      key="1"
-    >
+    <div>
       <Styled(Arguments)
         args={
           Array [
@@ -146,9 +124,7 @@ exports[`PropsRenderer should render parameters 1`] = `
         }
       />
     </div>
-    <div
-      key="2"
-    >
+    <div>
       <div>
         <Markdown
           text="Public"
@@ -162,28 +138,20 @@ exports[`PropsRenderer should render parameters 1`] = `
 
 exports[`PropsRenderer should render public method 1`] = `
 <ul>
-  <li
-    key="0"
-  >
-    <div
-      key="0"
-    >
+  <li>
+    <div>
       <Styled(Name)
         deprecated={false}
       >
         method()
       </Styled(Name)>
     </div>
-    <div
-      key="1"
-    >
+    <div>
       <Styled(Arguments)
         args={Array []}
       />
     </div>
-    <div
-      key="2"
-    >
+    <div>
       <div>
         <Markdown
           text="Public"
@@ -197,28 +165,20 @@ exports[`PropsRenderer should render public method 1`] = `
 
 exports[`PropsRenderer should render returns 1`] = `
 <ul>
-  <li
-    key="0"
-  >
-    <div
-      key="0"
-    >
+  <li>
+    <div>
       <Styled(Name)
         deprecated={false}
       >
         method()
       </Styled(Name)>
     </div>
-    <div
-      key="1"
-    >
+    <div>
       <Styled(Arguments)
         args={Array []}
       />
     </div>
-    <div
-      key="2"
-    >
+    <div>
       <div>
         <Styled(Argument)
           block={true}
diff --git a/src/client/rsg-components/Name/Name.spec.tsx b/src/client/rsg-components/Name/Name.spec.tsx
index 355ce71f..073d18a0 100644
--- a/src/client/rsg-components/Name/Name.spec.tsx
+++ b/src/client/rsg-components/Name/Name.spec.tsx
@@ -1,5 +1,5 @@
 import React from 'react';
-import { shallow } from 'enzyme';
+import { createRenderer } from 'react-test-renderer/shallow';
 import { NameRenderer, styles } from './NameRenderer';
 
 const props = {
@@ -7,17 +7,19 @@ const props = {
 };
 
 it('renderer should render argument name', () => {
-	const actual = shallow(<NameRenderer {...props}>Foo</NameRenderer>);
+	const renderer = createRenderer();
+	renderer.render(<NameRenderer {...props}>Foo</NameRenderer>);
 
-	expect(actual).toMatchSnapshot();
+	expect(renderer.getRenderOutput()).toMatchSnapshot();
 });
 
 it('renderer should render deprecated argument name', () => {
-	const actual = shallow(
+	const renderer = createRenderer();
+	renderer.render(
 		<NameRenderer {...props} deprecated>
 			Foo
 		</NameRenderer>
 	);
 
-	expect(actual).toMatchSnapshot();
+	expect(renderer.getRenderOutput()).toMatchSnapshot();
 });
diff --git a/src/client/rsg-components/NotFound/NotFound.spec.tsx b/src/client/rsg-components/NotFound/NotFound.spec.tsx
index b9635390..7440da19 100644
--- a/src/client/rsg-components/NotFound/NotFound.spec.tsx
+++ b/src/client/rsg-components/NotFound/NotFound.spec.tsx
@@ -1,9 +1,10 @@
 import React from 'react';
-import { shallow } from 'enzyme';
+import { createRenderer } from 'react-test-renderer/shallow';
 import { NotFoundRenderer } from './NotFoundRenderer';
 
 it('renderer should render not found message', () => {
-	const actual = shallow(<NotFoundRenderer classes={{}} />);
+	const renderer = createRenderer();
+	renderer.render(<NotFoundRenderer classes={{}} />);
 
-	expect(actual).toMatchSnapshot();
+	expect(renderer.getRenderOutput()).toMatchSnapshot();
 });
diff --git a/src/client/rsg-components/Para/Para.spec.tsx b/src/client/rsg-components/Para/Para.spec.tsx
index e2411c3b..684802ac 100644
--- a/src/client/rsg-components/Para/Para.spec.tsx
+++ b/src/client/rsg-components/Para/Para.spec.tsx
@@ -1,5 +1,5 @@
 import React from 'react';
-import { shallow } from 'enzyme';
+import { createRenderer } from 'react-test-renderer/shallow';
 import { ParaRenderer, styles } from './ParaRenderer';
 
 const props = {
@@ -7,17 +7,19 @@ const props = {
 };
 
 it('should render paragraph as a <div>', () => {
-	const actual = shallow(<ParaRenderer {...props}>Pizza</ParaRenderer>);
+	const renderer = createRenderer();
+	renderer.render(<ParaRenderer {...props}>Pizza</ParaRenderer>);
 
-	expect(actual).toMatchSnapshot();
+	expect(renderer.getRenderOutput()).toMatchSnapshot();
 });
 
 it('should render paragraph as a <p>', () => {
-	const actual = shallow(
+	const renderer = createRenderer();
+	renderer.render(
 		<ParaRenderer {...props} semantic="p">
 			Pizza
 		</ParaRenderer>
 	);
 
-	expect(actual).toMatchSnapshot();
+	expect(renderer.getRenderOutput()).toMatchSnapshot();
 });
diff --git a/src/client/rsg-components/Pathline/Pathline.spec.tsx b/src/client/rsg-components/Pathline/Pathline.spec.tsx
index 0090f4ac..91bed332 100644
--- a/src/client/rsg-components/Pathline/Pathline.spec.tsx
+++ b/src/client/rsg-components/Pathline/Pathline.spec.tsx
@@ -1,6 +1,7 @@
+import { fireEvent, render } from '@testing-library/react';
 import React from 'react';
 import copy from 'clipboard-copy';
-import { shallow, mount } from 'enzyme';
+import { createRenderer } from 'react-test-renderer/shallow';
 import { PathlineRenderer, styles } from './PathlineRenderer';
 
 jest.mock('clipboard-copy');
@@ -11,12 +12,13 @@ const props = {
 };
 
 it('renderer should a path line', () => {
-	const actual = shallow(<PathlineRenderer {...props}>{pathline}</PathlineRenderer>);
-	expect(actual).toMatchSnapshot();
+	const renderer = createRenderer();
+	renderer.render(<PathlineRenderer {...props}>{pathline}</PathlineRenderer>);
+	expect(renderer.getRenderOutput()).toMatchSnapshot();
 });
 
 test('should copy text on click', () => {
-	const actual = mount(<PathlineRenderer {...props}>{pathline}</PathlineRenderer>);
-	actual.find('button').simulate('click');
+	const { getByRole } = render(<PathlineRenderer {...props}>{pathline}</PathlineRenderer>);
+	fireEvent.click(getByRole('button'));
 	expect(copy).toBeCalledWith(pathline);
 });
diff --git a/src/client/rsg-components/PlaygroundError/PlaygroundError.spec.tsx b/src/client/rsg-components/PlaygroundError/PlaygroundError.spec.tsx
index 87cab1a4..9816ad4b 100644
--- a/src/client/rsg-components/PlaygroundError/PlaygroundError.spec.tsx
+++ b/src/client/rsg-components/PlaygroundError/PlaygroundError.spec.tsx
@@ -1,10 +1,11 @@
 import React from 'react';
-import { shallow } from 'enzyme';
+import { createRenderer } from 'react-test-renderer/shallow';
 import { PlaygroundErrorRenderer } from './PlaygroundErrorRenderer';
 
 it('renderer should render message', () => {
 	const message = 'Hello *world*!';
-	const actual = shallow(<PlaygroundErrorRenderer classes={{}} message={message} />);
+	const renderer = createRenderer();
+	renderer.render(<PlaygroundErrorRenderer classes={{}} message={message} />);
 
-	expect(actual).toMatchSnapshot();
+	expect(renderer.getRenderOutput()).toMatchSnapshot();
 });
diff --git a/src/client/rsg-components/Preview/Preview.spec.tsx b/src/client/rsg-components/Preview/Preview.spec.tsx
index 849d67ea..0bb40ac6 100644
--- a/src/client/rsg-components/Preview/Preview.spec.tsx
+++ b/src/client/rsg-components/Preview/Preview.spec.tsx
@@ -1,5 +1,4 @@
 import React from 'react';
-import { mount } from 'enzyme';
 import { render } from '@testing-library/react';
 import Preview from '.';
 import Context, { StyleGuideContextContents } from '../Context';
@@ -59,7 +58,7 @@ it('should not fail when Wrapper wasn’t mounted', () => {
 	const node = getByTestId('mountNode');
 
 	expect(
-		consoleError.mock.calls.find(call =>
+		consoleError.mock.calls.find((call) =>
 			call[0].toString().includes('ReferenceError: pizza is not defined')
 		)
 	).toBeTruthy();
@@ -123,7 +122,7 @@ it('should handle errors', () => {
 	);
 
 	expect(
-		consoleError.mock.calls.find(call =>
+		consoleError.mock.calls.find((call) =>
 			call[0].toString().includes('SyntaxError: Unexpected token')
 		)
 	).toBeTruthy();
@@ -131,7 +130,7 @@ it('should handle errors', () => {
 
 it('should not clear console on initial mount', () => {
 	console.clear = jest.fn();
-	mount(
+	render(
 		<Provider>
 			<Preview code={code} evalInContext={evalInContext} />
 		</Provider>
@@ -141,7 +140,7 @@ it('should not clear console on initial mount', () => {
 
 it('should clear console on second mount', () => {
 	console.clear = jest.fn();
-	mount(
+	render(
 		<Provider value={{ ...context, codeRevision: 1 }}>
 			<Preview code={code} evalInContext={evalInContext} />
 		</Provider>
diff --git a/src/client/rsg-components/ReactExample/ReactExample.spec.tsx b/src/client/rsg-components/ReactExample/ReactExample.spec.tsx
index 0de3acc8..415a817f 100644
--- a/src/client/rsg-components/ReactExample/ReactExample.spec.tsx
+++ b/src/client/rsg-components/ReactExample/ReactExample.spec.tsx
@@ -1,6 +1,8 @@
+import { fireEvent, render } from '@testing-library/react';
 import React from 'react';
-import { shallow, mount } from 'enzyme';
 import noop from 'lodash/noop';
+import renderer from 'react-test-renderer';
+import { createRenderer } from 'react-test-renderer/shallow';
 import ReactExample from '.';
 
 const evalInContext = (a: string): (() => any) =>
@@ -8,27 +10,31 @@ const evalInContext = (a: string): (() => any) =>
 	new Function('require', 'const React = require("react");' + a).bind(null, require);
 
 it('should render code', () => {
-	const actual = shallow(
+	const testRenderer = createRenderer();
+	testRenderer.render(
 		<ReactExample code={'<button>OK</button>'} evalInContext={evalInContext} onError={noop} />
 	);
 
-	expect(actual).toMatchSnapshot();
+	expect(testRenderer.getRenderOutput()).toMatchSnapshot();
 });
 
 it('should wrap code in Fragment when it starts with <', () => {
-	const actual = mount(
+	const actual = renderer.create(
 		<div>
 			<ReactExample code="<span /><span />" evalInContext={evalInContext} onError={noop} />
 		</div>
 	);
 
-	expect(actual.html()).toMatchSnapshot();
+	expect(actual.toJSON()).toMatchSnapshot();
 });
 
 it('should handle errors', () => {
 	const onError = jest.fn();
 
-	shallow(<ReactExample code={'<invalid code'} evalInContext={evalInContext} onError={onError} />);
+	const testRenderer = createRenderer();
+	testRenderer.render(
+		<ReactExample code={'<invalid code'} evalInContext={evalInContext} onError={onError} />
+	);
 
 	expect(onError).toHaveBeenCalledTimes(1);
 });
@@ -38,9 +44,11 @@ it('should set initial state with hooks', () => {
 const [count, setCount] = React.useState(0);
 <button>{count}</button>
 	`;
-	const actual = mount(<ReactExample code={code} evalInContext={evalInContext} onError={noop} />);
+	const { getByRole } = render(
+		<ReactExample code={code} evalInContext={evalInContext} onError={noop} />
+	);
 
-	expect(actual.find('button').text()).toEqual('0');
+	expect(getByRole('button').textContent).toEqual('0');
 });
 
 it('should update state with hooks', () => {
@@ -48,8 +56,10 @@ it('should update state with hooks', () => {
 const [count, setCount] = React.useState(0);
 <button onClick={() => setCount(count+1)}>{count}</button>
 	`;
-	const actual = mount(<ReactExample code={code} evalInContext={evalInContext} onError={noop} />);
-	actual.find('button').simulate('click');
+	const { getByRole } = render(
+		<ReactExample code={code} evalInContext={evalInContext} onError={noop} />
+	);
+	fireEvent.click(getByRole('button'));
 
-	expect(actual.find('button').text()).toEqual('1');
+	expect(getByRole('button').textContent).toEqual('1');
 });
diff --git a/src/client/rsg-components/ReactExample/__snapshots__/ReactExample.spec.tsx.snap b/src/client/rsg-components/ReactExample/__snapshots__/ReactExample.spec.tsx.snap
index 6b3e52b4..2552cfeb 100644
--- a/src/client/rsg-components/ReactExample/__snapshots__/ReactExample.spec.tsx.snap
+++ b/src/client/rsg-components/ReactExample/__snapshots__/ReactExample.spec.tsx.snap
@@ -10,9 +10,7 @@ exports[`should render code 1`] = `
 
 exports[`should wrap code in Fragment when it starts with < 1`] = `
 <div>
-  <span>
-  </span>
-  <span>
-  </span>
+  <span />
+  <span />
 </div>
 `;
diff --git a/src/client/rsg-components/SectionHeading/SectionHeading.spec.tsx b/src/client/rsg-components/SectionHeading/SectionHeading.spec.tsx
index 7a6a01b7..73c541eb 100644
--- a/src/client/rsg-components/SectionHeading/SectionHeading.spec.tsx
+++ b/src/client/rsg-components/SectionHeading/SectionHeading.spec.tsx
@@ -1,5 +1,6 @@
 import React from 'react';
-import { shallow, mount } from 'enzyme';
+import renderer from 'react-test-renderer';
+import { createRenderer } from 'react-test-renderer/shallow';
 import SectionHeading from './index';
 import SectionHeadingRenderer from './SectionHeadingRenderer';
 
@@ -7,7 +8,8 @@ describe('SectionHeading', () => {
 	const FakeToolbar = () => <div>Fake toolbar</div>;
 
 	test('should forward slot properties to the toolbar', () => {
-		const actual = shallow(
+		const testRenderer = createRenderer();
+		testRenderer.render(
 			<SectionHeading
 				id="section"
 				slotName="slot"
@@ -19,21 +21,21 @@ describe('SectionHeading', () => {
 			</SectionHeading>
 		);
 
-		expect(actual).toMatchSnapshot();
+		expect(testRenderer.getRenderOutput()).toMatchSnapshot();
 	});
 
 	test('render a section heading', () => {
-		const actual = mount(
+		const actual = renderer.create(
 			<SectionHeadingRenderer id="section" href="/section" depth={2} toolbar={<FakeToolbar />}>
 				A Section
 			</SectionHeadingRenderer>
 		);
 
-		expect(actual.find('h2')).toMatchSnapshot();
+		expect(actual.toJSON()).toMatchSnapshot();
 	});
 
 	test('render a deprecated section heading', () => {
-		const actual = mount(
+		const actual = renderer.create(
 			<SectionHeadingRenderer
 				id="section"
 				href="/section"
@@ -45,16 +47,16 @@ describe('SectionHeading', () => {
 			</SectionHeadingRenderer>
 		);
 
-		expect(actual.find('h2')).toMatchSnapshot();
+		expect(actual.toJSON()).toMatchSnapshot();
 	});
 
 	test('prevent the heading level from exceeding the maximum allowed by the Heading component', () => {
-		const actual = mount(
+		const actual = renderer.create(
 			<SectionHeadingRenderer id="section" href="/section" depth={7} toolbar={<FakeToolbar />}>
 				A Section
 			</SectionHeadingRenderer>
 		);
 
-		expect(actual.find('h6')).toHaveLength(1);
+		expect(actual.toJSON()).toMatchSnapshot();
 	});
 });
diff --git a/src/client/rsg-components/SectionHeading/__snapshots__/SectionHeading.spec.tsx.snap b/src/client/rsg-components/SectionHeading/__snapshots__/SectionHeading.spec.tsx.snap
index ade7e333..7ceb9086 100644
--- a/src/client/rsg-components/SectionHeading/__snapshots__/SectionHeading.spec.tsx.snap
+++ b/src/client/rsg-components/SectionHeading/__snapshots__/SectionHeading.spec.tsx.snap
@@ -1,31 +1,78 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
+exports[`SectionHeading prevent the heading level from exceeding the maximum allowed by the Heading component 1`] = `
+<div
+  className="rsg--wrapper-0"
+>
+  <h6
+    className="rsg--heading-5 rsg--heading6-11"
+    id="section"
+  >
+    <a
+      className="rsg--sectionName-2"
+      href="/section"
+    >
+      A Section
+    </a>
+  </h6>
+  <div
+    className="rsg--toolbar-1"
+  >
+    <div>
+      Fake toolbar
+    </div>
+  </div>
+</div>
+`;
+
 exports[`SectionHeading render a deprecated section heading 1`] = `
-<h2
-  className="rsg--heading-5 rsg--heading2-7"
-  id="section"
+<div
+  className="rsg--wrapper-0"
 >
-  <a
-    className="rsg--sectionName-2 rsg--isDeprecated-3"
-    href="/section"
+  <h2
+    className="rsg--heading-5 rsg--heading2-7"
+    id="section"
+  >
+    <a
+      className="rsg--sectionName-2 rsg--isDeprecated-3"
+      href="/section"
+    >
+      A Section
+    </a>
+  </h2>
+  <div
+    className="rsg--toolbar-1"
   >
-    A Section
-  </a>
-</h2>
+    <div>
+      Fake toolbar
+    </div>
+  </div>
+</div>
 `;
 
 exports[`SectionHeading render a section heading 1`] = `
-<h2
-  className="rsg--heading-5 rsg--heading2-7"
-  id="section"
+<div
+  className="rsg--wrapper-0"
 >
-  <a
-    className="rsg--sectionName-2"
-    href="/section"
+  <h2
+    className="rsg--heading-5 rsg--heading2-7"
+    id="section"
+  >
+    <a
+      className="rsg--sectionName-2"
+      href="/section"
+    >
+      A Section
+    </a>
+  </h2>
+  <div
+    className="rsg--toolbar-1"
   >
-    A Section
-  </a>
-</h2>
+    <div>
+      Fake toolbar
+    </div>
+  </div>
+</div>
 `;
 
 exports[`SectionHeading should forward slot properties to the toolbar 1`] = `
diff --git a/src/client/rsg-components/Sections/Sections.spec.tsx b/src/client/rsg-components/Sections/Sections.spec.tsx
index 3039bc08..44b1443e 100644
--- a/src/client/rsg-components/Sections/Sections.spec.tsx
+++ b/src/client/rsg-components/Sections/Sections.spec.tsx
@@ -1,5 +1,5 @@
 import React from 'react';
-import { shallow } from 'enzyme';
+import { createRenderer } from 'react-test-renderer/shallow';
 import noop from 'lodash/noop';
 import Section from '../Section';
 import Sections from './Sections';
@@ -42,13 +42,15 @@ const sections = [
 ] as any;
 
 it('should render component renderer', () => {
-	const actual = shallow(<Sections sections={sections} depth={3} />);
+	const renderer = createRenderer();
+	renderer.render(<Sections sections={sections} depth={3} />);
 
-	expect(actual).toMatchSnapshot();
+	expect(renderer.getRenderOutput()).toMatchSnapshot();
 });
 
 it('render should render styled component', () => {
-	const actual = shallow(
+	const renderer = createRenderer();
+	renderer.render(
 		<StyledSectionsRenderer>
 			<Section key={0} section={sections[0]} depth={3} />
 			<Section key={1} section={sections[1]} depth={3} />
@@ -56,11 +58,12 @@ it('render should render styled component', () => {
 		</StyledSectionsRenderer>
 	);
 
-	expect(actual).toMatchSnapshot();
+	expect(renderer.getRenderOutput()).toMatchSnapshot();
 });
 
 it('render should render component', () => {
-	const actual = shallow(
+	const renderer = createRenderer();
+	renderer.render(
 		<SectionsRenderer classes={{}}>
 			<Section key={0} section={sections[0]} depth={3} />
 			<Section key={1} section={sections[1]} depth={3} />
@@ -68,5 +71,5 @@ it('render should render component', () => {
 		</SectionsRenderer>
 	);
 
-	expect(actual).toMatchSnapshot();
+	expect(renderer.getRenderOutput()).toMatchSnapshot();
 });
diff --git a/src/client/rsg-components/Sections/__snapshots__/Sections.spec.tsx.snap b/src/client/rsg-components/Sections/__snapshots__/Sections.spec.tsx.snap
index 64e700fe..b642556d 100644
--- a/src/client/rsg-components/Sections/__snapshots__/Sections.spec.tsx.snap
+++ b/src/client/rsg-components/Sections/__snapshots__/Sections.spec.tsx.snap
@@ -4,15 +4,12 @@ exports[`render should render component 1`] = `
 <section>
   <Section
     depth={3}
-    key="0"
     section={
       Object {
         "components": Array [],
         "content": Array [
           Object {
-            "content": <button>
-  OK
-</button>,
+            "content": "<button>OK</button>",
             "evalInContext": [Function],
             "type": "code",
           },
@@ -23,7 +20,6 @@ exports[`render should render component 1`] = `
   />
   <Section
     depth={3}
-    key="1"
     section={
       Object {
         "components": Array [],
@@ -39,7 +35,6 @@ exports[`render should render component 1`] = `
   />
   <Section
     depth={3}
-    key="2"
     section={
       Object {
         "sections": Array [
@@ -68,15 +63,12 @@ exports[`render should render styled component 1`] = `
 >
   <Section
     depth={3}
-    key="0"
     section={
       Object {
         "components": Array [],
         "content": Array [
           Object {
-            "content": <button>
-  OK
-</button>,
+            "content": "<button>OK</button>",
             "evalInContext": [Function],
             "type": "code",
           },
@@ -87,7 +79,6 @@ exports[`render should render styled component 1`] = `
   />
   <Section
     depth={3}
-    key="1"
     section={
       Object {
         "components": Array [],
@@ -103,7 +94,6 @@ exports[`render should render styled component 1`] = `
   />
   <Section
     depth={3}
-    key="2"
     section={
       Object {
         "sections": Array [
@@ -126,15 +116,12 @@ exports[`should render component renderer 1`] = `
 <Styled(Sections)>
   <Section
     depth={3}
-    key="0"
     section={
       Object {
         "components": Array [],
         "content": Array [
           Object {
-            "content": <button>
-  OK
-</button>,
+            "content": "<button>OK</button>",
             "evalInContext": [Function],
             "type": "code",
           },
@@ -145,7 +132,6 @@ exports[`should render component renderer 1`] = `
   />
   <Section
     depth={3}
-    key="1"
     section={
       Object {
         "components": Array [],
@@ -161,7 +147,6 @@ exports[`should render component renderer 1`] = `
   />
   <Section
     depth={3}
-    key="2"
     section={
       Object {
         "sections": Array [
diff --git a/src/client/rsg-components/Table/Table.spec.tsx b/src/client/rsg-components/Table/Table.spec.tsx
index 5971e9bc..84b18624 100644
--- a/src/client/rsg-components/Table/Table.spec.tsx
+++ b/src/client/rsg-components/Table/Table.spec.tsx
@@ -1,5 +1,5 @@
 import React from 'react';
-import { shallow } from 'enzyme';
+import { createRenderer } from 'react-test-renderer/shallow';
 import { TableRenderer, styles } from './TableRenderer';
 
 const columns = [
@@ -25,7 +25,8 @@ const props = {
 };
 
 it('should render a table', () => {
-	const actual = shallow(<TableRenderer {...props} columns={columns} rows={rows} />);
+	const renderer = createRenderer();
+	renderer.render(<TableRenderer {...props} columns={columns} rows={rows} />);
 
-	expect(actual).toMatchSnapshot();
+	expect(renderer.getRenderOutput()).toMatchSnapshot();
 });
diff --git a/src/client/rsg-components/Table/__snapshots__/Table.spec.tsx.snap b/src/client/rsg-components/Table/__snapshots__/Table.spec.tsx.snap
index 127715c8..6b2bdeb7 100644
--- a/src/client/rsg-components/Table/__snapshots__/Table.spec.tsx.snap
+++ b/src/client/rsg-components/Table/__snapshots__/Table.spec.tsx.snap
@@ -10,25 +10,20 @@ exports[`should render a table 1`] = `
     <tr>
       <th
         className="cellHeading"
-        key="Name"
       >
         Name
       </th>
       <th
         className="cellHeading"
-        key="Type"
       >
         Type
       </th>
     </tr>
   </thead>
   <tbody>
-    <tr
-      key="Quattro formaggi"
-    >
+    <tr>
       <td
         className="cell"
-        key="0"
       >
         <span>
           name: 
@@ -37,7 +32,6 @@ exports[`should render a table 1`] = `
       </td>
       <td
         className="cell"
-        key="1"
       >
         <span>
           type: 
@@ -45,12 +39,9 @@ exports[`should render a table 1`] = `
         </span>
       </td>
     </tr>
-    <tr
-      key="Tiramisu"
-    >
+    <tr>
       <td
         className="cell"
-        key="0"
       >
         <span>
           name: 
@@ -59,7 +50,6 @@ exports[`should render a table 1`] = `
       </td>
       <td
         className="cell"
-        key="1"
       >
         <span>
           type: 
@@ -67,12 +57,9 @@ exports[`should render a table 1`] = `
         </span>
       </td>
     </tr>
-    <tr
-      key="Unicorn"
-    >
+    <tr>
       <td
         className="cell"
-        key="0"
       >
         <span>
           name: 
@@ -81,7 +68,6 @@ exports[`should render a table 1`] = `
       </td>
       <td
         className="cell"
-        key="1"
       >
         <span>
           type: 
diff --git a/src/client/rsg-components/TableOfContents/TableOfContents.spec.tsx b/src/client/rsg-components/TableOfContents/TableOfContents.spec.tsx
index 7f3c05c5..8bfddfcc 100644
--- a/src/client/rsg-components/TableOfContents/TableOfContents.spec.tsx
+++ b/src/client/rsg-components/TableOfContents/TableOfContents.spec.tsx
@@ -1,6 +1,6 @@
 import React from 'react';
 import { render, fireEvent } from '@testing-library/react';
-import { shallow } from 'enzyme';
+import { createRenderer } from 'react-test-renderer/shallow';
 import TableOfContents from './TableOfContents';
 import { TableOfContentsRenderer } from './TableOfContentsRenderer';
 import Context from '../Context';
@@ -105,7 +105,7 @@ it('should call a callback when input value changed', () => {
 	const onSearchTermChange = jest.fn();
 	const searchTerm = 'foo';
 	const newSearchTerm = 'bar';
-	const actual = shallow(
+	const { getByRole } = render(
 		<TableOfContentsRenderer
 			classes={{}}
 			searchTerm={searchTerm}
@@ -115,101 +115,118 @@ it('should call a callback when input value changed', () => {
 		</TableOfContentsRenderer>
 	);
 
-	actual.find('input').simulate('change', {
-		target: {
-			value: newSearchTerm,
-		},
-	});
+	fireEvent.change(getByRole('textbox'), { target: { value: newSearchTerm } });
 
 	expect(onSearchTermChange).toBeCalledWith(newSearchTerm);
 });
 
 it('should render content of subsections of a section that has no components', () => {
-	const actual = shallow(
+	const renderer = createRenderer();
+	renderer.render(
 		<TableOfContents
 			sections={[{ sections: [{ content: 'intro.md' }, { content: 'chapter.md' }] }]}
 		/>
 	);
 
-	expect(actual.find('ComponentsList').prop('items')).toMatchInlineSnapshot(`
-		Array [
-		  Object {
-		    "components": Array [],
-		    "content": undefined,
-		    "forcedOpen": false,
-		    "heading": false,
-		    "initialOpen": true,
-		    "sections": Array [],
-		    "selected": false,
-		    "shouldOpenInNewTab": false,
-		  },
-		  Object {
-		    "components": Array [],
-		    "content": undefined,
-		    "forcedOpen": false,
-		    "heading": false,
-		    "initialOpen": true,
-		    "sections": Array [],
-		    "selected": false,
-		    "shouldOpenInNewTab": false,
-		  },
-		]
+	expect(renderer.getRenderOutput()).toMatchInlineSnapshot(`
+		<Styled(TableOfContents)
+		  onSearchTermChange={[Function]}
+		  searchTerm=""
+		>
+		  <ComponentsList
+		    items={
+		      Array [
+		        Object {
+		          "components": Array [],
+		          "content": undefined,
+		          "forcedOpen": false,
+		          "heading": false,
+		          "initialOpen": true,
+		          "sections": Array [],
+		          "selected": false,
+		          "shouldOpenInNewTab": false,
+		        },
+		        Object {
+		          "components": Array [],
+		          "content": undefined,
+		          "forcedOpen": false,
+		          "heading": false,
+		          "initialOpen": true,
+		          "sections": Array [],
+		          "selected": false,
+		          "shouldOpenInNewTab": false,
+		        },
+		      ]
+		    }
+		  />
+		</Styled(TableOfContents)>
 	`);
 });
 
 it('should render components of a single top section as root', () => {
-	const actual = shallow(<TableOfContents sections={[{ components }]} />);
+	const renderer = createRenderer();
+	renderer.render(<TableOfContents sections={[{ components }]} />);
 
-	expect(actual.find('ComponentsList').prop('items')).toMatchInlineSnapshot(`
-		Array [
-		  Object {
-		    "components": Array [],
-		    "content": undefined,
-		    "forcedOpen": false,
-		    "heading": false,
-		    "href": "#button",
-		    "initialOpen": true,
-		    "name": "Button",
-		    "sections": Array [],
-		    "selected": false,
-		    "shouldOpenInNewTab": false,
-		    "slug": "button",
-		    "visibleName": "Button",
-		  },
-		  Object {
-		    "components": Array [],
-		    "content": undefined,
-		    "forcedOpen": false,
-		    "heading": false,
-		    "href": "#input",
-		    "initialOpen": true,
-		    "name": "Input",
-		    "sections": Array [],
-		    "selected": false,
-		    "shouldOpenInNewTab": false,
-		    "slug": "input",
-		    "visibleName": "Input",
-		  },
-		  Object {
-		    "components": Array [],
-		    "content": undefined,
-		    "forcedOpen": false,
-		    "heading": false,
-		    "href": "#textarea",
-		    "initialOpen": true,
-		    "name": "Textarea",
-		    "sections": Array [],
-		    "selected": false,
-		    "shouldOpenInNewTab": false,
-		    "slug": "textarea",
-		    "visibleName": "Textarea",
-		  },
-		]
-	`);
+	expect(renderer.getRenderOutput()).toMatchInlineSnapshot(`
+<Styled(TableOfContents)
+  onSearchTermChange={[Function]}
+  searchTerm=""
+>
+  <ComponentsList
+    items={
+      Array [
+        Object {
+          "components": Array [],
+          "content": undefined,
+          "forcedOpen": false,
+          "heading": false,
+          "href": "#button",
+          "initialOpen": true,
+          "name": "Button",
+          "sections": Array [],
+          "selected": false,
+          "shouldOpenInNewTab": false,
+          "slug": "button",
+          "visibleName": "Button",
+        },
+        Object {
+          "components": Array [],
+          "content": undefined,
+          "forcedOpen": false,
+          "heading": false,
+          "href": "#input",
+          "initialOpen": true,
+          "name": "Input",
+          "sections": Array [],
+          "selected": false,
+          "shouldOpenInNewTab": false,
+          "slug": "input",
+          "visibleName": "Input",
+        },
+        Object {
+          "components": Array [],
+          "content": undefined,
+          "forcedOpen": false,
+          "heading": false,
+          "href": "#textarea",
+          "initialOpen": true,
+          "name": "Textarea",
+          "sections": Array [],
+          "selected": false,
+          "shouldOpenInNewTab": false,
+          "slug": "textarea",
+          "visibleName": "Textarea",
+        },
+      ]
+    }
+  />
+</Styled(TableOfContents)>
+`);
 });
 
 it('should render as the link will open in a new window only if external presents as true', () => {
-	const actual = shallow(
+	const renderer = createRenderer();
+	renderer.render(
 		<TableOfContents
 			sections={[
 				{
@@ -222,33 +239,42 @@ it('should render as the link will open in a new window only if external present
 		/>
 	);
 
-	expect(actual.find('ComponentsList').prop('items')).toMatchInlineSnapshot(`
-		Array [
-		  Object {
-		    "components": Array [],
-		    "content": undefined,
-		    "forcedOpen": false,
-		    "heading": false,
-		    "href": "http://example.com",
-		    "initialOpen": true,
-		    "sections": Array [],
-		    "selected": false,
-		    "shouldOpenInNewTab": false,
-		  },
-		  Object {
-		    "components": Array [],
-		    "content": undefined,
-		    "external": true,
-		    "forcedOpen": false,
-		    "heading": false,
-		    "href": "http://example.com",
-		    "initialOpen": true,
-		    "sections": Array [],
-		    "selected": false,
-		    "shouldOpenInNewTab": false,
-		  },
-		]
-	`);
+	expect(renderer.getRenderOutput()).toMatchInlineSnapshot(`
+<Styled(TableOfContents)
+  onSearchTermChange={[Function]}
+  searchTerm=""
+>
+  <ComponentsList
+    items={
+      Array [
+        Object {
+          "components": Array [],
+          "content": undefined,
+          "forcedOpen": false,
+          "heading": false,
+          "href": "http://example.com",
+          "initialOpen": true,
+          "sections": Array [],
+          "selected": false,
+          "shouldOpenInNewTab": false,
+        },
+        Object {
+          "components": Array [],
+          "content": undefined,
+          "external": true,
+          "forcedOpen": false,
+          "heading": false,
+          "href": "http://example.com",
+          "initialOpen": true,
+          "sections": Array [],
+          "selected": false,
+          "shouldOpenInNewTab": false,
+        },
+      ]
+    }
+  />
+</Styled(TableOfContents)>
+`);
 });
 
 /**
diff --git a/src/client/rsg-components/Text/Text.spec.tsx b/src/client/rsg-components/Text/Text.spec.tsx
index 046ead09..ccbd6820 100644
--- a/src/client/rsg-components/Text/Text.spec.tsx
+++ b/src/client/rsg-components/Text/Text.spec.tsx
@@ -1,5 +1,5 @@
 import React from 'react';
-import { shallow } from 'enzyme';
+import { createRenderer } from 'react-test-renderer/shallow';
 import { TextRenderer, styles } from './TextRenderer';
 
 const props = {
@@ -8,58 +8,64 @@ const props = {
 
 describe('Text', () => {
 	it('should render text', () => {
-		const actual = shallow(<TextRenderer {...props}>Pizza</TextRenderer>);
+		const renderer = createRenderer();
+		renderer.render(<TextRenderer {...props}>Pizza</TextRenderer>);
 
-		expect(actual).toMatchSnapshot();
+		expect(renderer.getRenderOutput()).toMatchSnapshot();
 	});
 
 	it('should render underlined text', () => {
-		const actual = shallow(
+		const renderer = createRenderer();
+		renderer.render(
 			<TextRenderer {...props} underlined>
 				Pizza
 			</TextRenderer>
 		);
 
-		expect(actual).toMatchSnapshot();
+		expect(renderer.getRenderOutput()).toMatchSnapshot();
 	});
 
 	it('should render sized text', () => {
-		const actual = shallow(
+		const renderer = createRenderer();
+		renderer.render(
 			<TextRenderer {...props} size="small">
 				Pizza
 			</TextRenderer>
 		);
 
-		expect(actual).toMatchSnapshot();
+		expect(renderer.getRenderOutput()).toMatchSnapshot();
 	});
 
 	it('should render colored text', () => {
-		const actual = shallow(
+		const renderer = createRenderer();
+		renderer.render(
 			<TextRenderer {...props} color="light">
 				Pizza
 			</TextRenderer>
 		);
 
-		expect(actual).toMatchSnapshot();
+		expect(renderer.getRenderOutput()).toMatchSnapshot();
 	});
 
 	it('should render text with a semantic tag and styles', () => {
-		const actual = shallow(
+		const renderer = createRenderer();
+		renderer.render(
 			<TextRenderer {...props} semantic="strong">
 				Pizza
 			</TextRenderer>
 		);
 
-		expect(actual).toMatchSnapshot();
+		expect(renderer.getRenderOutput()).toMatchSnapshot();
 	});
 
 	it('should render text with a title', () => {
-		const actual = shallow(
+		const renderer = createRenderer();
+		renderer.render(
 			<TextRenderer {...props} title="Pasta">
 				Pizza
 			</TextRenderer>
 		);
 
-		expect(actual).toMatchSnapshot();
+		expect(renderer.getRenderOutput()).toMatchSnapshot();
 	});
 });
diff --git a/src/client/rsg-components/ToolbarButton/ToolbarButton.spec.tsx b/src/client/rsg-components/ToolbarButton/ToolbarButton.spec.tsx
index 7039178c..58e99b6a 100644
--- a/src/client/rsg-components/ToolbarButton/ToolbarButton.spec.tsx
+++ b/src/client/rsg-components/ToolbarButton/ToolbarButton.spec.tsx
@@ -1,5 +1,5 @@
 import React from 'react';
-import { shallow } from 'enzyme';
+import { createRenderer } from 'react-test-renderer/shallow';
 import { ToolbarButtonRenderer, styles } from './ToolbarButtonRenderer';
 
 const props = {
@@ -8,51 +8,56 @@ const props = {
 };
 
 it('should render a button', () => {
-	const actual = shallow(
+	const renderer = createRenderer();
+	renderer.render(
 		<ToolbarButtonRenderer {...props} onClick={() => {}}>
 			pizza
 		</ToolbarButtonRenderer>
 	);
 
-	expect(actual).toMatchSnapshot();
+	expect(renderer.getRenderOutput()).toMatchSnapshot();
 });
 
 it('should render a link', () => {
-	const actual = shallow(
+	const renderer = createRenderer();
+	renderer.render(
 		<ToolbarButtonRenderer {...props} href="/foo">
 			pizza
 		</ToolbarButtonRenderer>
 	);
 
-	expect(actual).toMatchSnapshot();
+	expect(renderer.getRenderOutput()).toMatchSnapshot();
 });
 
 it('should pass a class name to a button', () => {
-	const actual = shallow(
+	const renderer = createRenderer();
+	renderer.render(
 		<ToolbarButtonRenderer {...props} onClick={() => {}} className="foo-class">
 			pizza
 		</ToolbarButtonRenderer>
 	);
 
-	expect(actual.prop('className')).toBe('button foo-class');
+	expect(renderer.getRenderOutput()).toMatchSnapshot();
 });
 
 it('should pass a class name to a link', () => {
-	const actual = shallow(
+	const renderer = createRenderer();
+	renderer.render(
 		<ToolbarButtonRenderer {...props} href="/foo" className="foo-class">
 			pizza
 		</ToolbarButtonRenderer>
 	);
 
-	expect(actual.prop('className')).toBe('button foo-class');
+	expect(renderer.getRenderOutput()).toMatchSnapshot();
 });
 
 it('should render a button with small styles', () => {
-	const actual = shallow(
+	const renderer = createRenderer();
+	renderer.render(
 		<ToolbarButtonRenderer {...props} onClick={() => {}} small>
 			butterbrot
 		</ToolbarButtonRenderer>
 	);
 
-	expect(actual.prop('className')).toBe('button isSmall');
+	expect(renderer.getRenderOutput()).toMatchSnapshot();
 });
diff --git a/src/client/rsg-components/ToolbarButton/__snapshots__/ToolbarButton.spec.tsx.snap b/src/client/rsg-components/ToolbarButton/__snapshots__/ToolbarButton.spec.tsx.snap
index 9474b36d..873af79e 100644
--- a/src/client/rsg-components/ToolbarButton/__snapshots__/ToolbarButton.spec.tsx.snap
+++ b/src/client/rsg-components/ToolbarButton/__snapshots__/ToolbarButton.spec.tsx.snap
@@ -1,5 +1,28 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
+exports[`should pass a class name to a button 1`] = `
+<button
+  aria-label="Pizza button"
+  className="button foo-class"
+  onClick={[Function]}
+  title="Pizza button"
+  type="button"
+>
+  pizza
+</button>
+`;
+
+exports[`should pass a class name to a link 1`] = `
+<a
+  aria-label="Pizza button"
+  className="button foo-class"
+  href="/foo"
+  title="Pizza button"
+>
+  pizza
+</a>
+`;
+
 exports[`should render a button 1`] = `
 <button
   aria-label="Pizza button"
@@ -12,6 +35,18 @@ exports[`should render a button 1`] = `
 </button>
 `;
 
+exports[`should render a button with small styles 1`] = `
+<button
+  aria-label="Pizza button"
+  className="button isSmall"
+  onClick={[Function]}
+  title="Pizza button"
+  type="button"
+>
+  butterbrot
+</button>
+`;
+
 exports[`should render a link 1`] = `
 <a
   aria-label="Pizza button"
diff --git a/src/client/rsg-components/Type/Type.spec.tsx b/src/client/rsg-components/Type/Type.spec.tsx
index 54cb9f31..ab4136aa 100644
--- a/src/client/rsg-components/Type/Type.spec.tsx
+++ b/src/client/rsg-components/Type/Type.spec.tsx
@@ -1,5 +1,5 @@
 import React from 'react';
-import { shallow } from 'enzyme';
+import { createRenderer } from 'react-test-renderer/shallow';
 import { TypeRenderer, styles } from './TypeRenderer';
 
 const props = {
@@ -7,7 +7,8 @@ const props = {
 };
 
 it('renderer should render type', () => {
-	const actual = shallow(<TypeRenderer {...props}>Array</TypeRenderer>);
+	const renderer = createRenderer();
+	renderer.render(<TypeRenderer {...props}>Array</TypeRenderer>);
 
-	expect(actual).toMatchSnapshot();
+	expect(renderer.getRenderOutput()).toMatchSnapshot();
 });
diff --git a/src/client/rsg-components/Usage/Usage.spec.tsx b/src/client/rsg-components/Usage/Usage.spec.tsx
index b230bc3b..7f34113b 100644
--- a/src/client/rsg-components/Usage/Usage.spec.tsx
+++ b/src/client/rsg-components/Usage/Usage.spec.tsx
@@ -1,5 +1,5 @@
 import React from 'react';
-import { shallow } from 'enzyme';
+import { createRenderer } from 'react-test-renderer/shallow';
 import { PropTypeDescriptor, MethodDescriptor } from 'react-docgen';
 import Usage from './Usage';
 
@@ -28,20 +28,23 @@ const methods: MethodDescriptor[] = [
 
 describe('Usage', () => {
 	it('should render props table', () => {
-		const actual = shallow(<Usage props={{ props }} />);
+		const renderer = createRenderer();
+		renderer.render(<Usage props={{ props }} />);
 
-		expect(actual).toMatchSnapshot();
+		expect(renderer.getRenderOutput()).toMatchSnapshot();
 	});
 
 	it('should render methods table', () => {
-		const actual = shallow(<Usage props={{ methods }} />);
+		const renderer = createRenderer();
+		renderer.render(<Usage props={{ methods }} />);
 
-		expect(actual).toMatchSnapshot();
+		expect(renderer.getRenderOutput()).toMatchSnapshot();
 	});
 
 	it('should render nothing without props and methods', () => {
-		const actual = shallow(<Usage props={{}} />);
+		const renderer = createRenderer();
+		renderer.render(<Usage props={{}} />);
 
-		expect(actual.getElement()).toBe(null);
+		expect(renderer.getRenderOutput()).toBe(null);
 	});
 });
diff --git a/src/client/rsg-components/Version/Version.spec.tsx b/src/client/rsg-components/Version/Version.spec.tsx
index 974f300c..a835e161 100644
--- a/src/client/rsg-components/Version/Version.spec.tsx
+++ b/src/client/rsg-components/Version/Version.spec.tsx
@@ -1,9 +1,9 @@
 import React from 'react';
-import { render } from 'enzyme';
+import renderer from 'react-test-renderer';
 import VersionRenderer from './VersionRenderer';
 
 it('renderer should render version', () => {
-	const actual = render(<VersionRenderer>1.2.3-a</VersionRenderer>);
+	const actual = renderer.create(<VersionRenderer>1.2.3-a</VersionRenderer>);
 
-	expect(actual).toMatchSnapshot();
+	expect(actual.toJSON()).toMatchSnapshot();
 });
diff --git a/src/client/rsg-components/Version/__snapshots__/Version.spec.tsx.snap b/src/client/rsg-components/Version/__snapshots__/Version.spec.tsx.snap
index fa39be1e..294e30cd 100644
--- a/src/client/rsg-components/Version/__snapshots__/Version.spec.tsx.snap
+++ b/src/client/rsg-components/Version/__snapshots__/Version.spec.tsx.snap
@@ -3,7 +3,7 @@
 exports[`renderer should render version 1`] = `
 <p
   aria-label="version"
-  class="rsg--version-0"
+  className="rsg--version-0"
 >
   1.2.3-a
 </p>
diff --git a/src/client/rsg-components/Welcome/Welcome.spec.tsx b/src/client/rsg-components/Welcome/Welcome.spec.tsx
index fc2b8848..62fa8f4c 100644
--- a/src/client/rsg-components/Welcome/Welcome.spec.tsx
+++ b/src/client/rsg-components/Welcome/Welcome.spec.tsx
@@ -1,9 +1,10 @@
 import React from 'react';
-import { shallow } from 'enzyme';
+import { createRenderer } from 'react-test-renderer/shallow';
 import { WelcomeRenderer } from './WelcomeRenderer';
 
 it('renderer should render welcome screen', () => {
-	const actual = shallow(<WelcomeRenderer classes={{}} patterns={['foo/*.js', 'bar/*.js']} />);
+	const renderer = createRenderer();
+	renderer.render(<WelcomeRenderer classes={{}} patterns={['foo/*.js', 'bar/*.js']} />);
 
-	expect(actual).toMatchSnapshot();
+	expect(renderer.getRenderOutput()).toMatchSnapshot();
 });
diff --git a/src/client/rsg-components/Wrapper/Wrapper.spec.tsx b/src/client/rsg-components/Wrapper/Wrapper.spec.tsx
index ba506938..b5ab3c49 100644
--- a/src/client/rsg-components/Wrapper/Wrapper.spec.tsx
+++ b/src/client/rsg-components/Wrapper/Wrapper.spec.tsx
@@ -1,23 +1,25 @@
 import React from 'react';
-import { shallow } from 'enzyme';
+import { createRenderer } from 'react-test-renderer/shallow';
 import Wrapper from './Wrapper';
 
 it('should render children', () => {
 	const children = <span>Hello</span>;
-	const actual = shallow(<Wrapper onError={() => {}}>{children}</Wrapper>);
+	const renderer = createRenderer();
+	renderer.render(<Wrapper onError={() => {}}>{children}</Wrapper>);
 
-	expect(actual).toMatchSnapshot();
+	expect(renderer.getRenderOutput()).toMatchSnapshot();
 });
 
 it('should call onError handler when React invokes error handler', () => {
 	const onError = jest.fn();
-	const actual = shallow(<Wrapper onError={onError}>blah</Wrapper>);
+	const renderer = createRenderer();
+	renderer.render(<Wrapper onError={onError}>blah</Wrapper>);
 
 	// faux error
 	const err = new Error('err');
-	const inst = actual.instance();
+	const inst = renderer.getMountedInstance() as Wrapper;
 	if (inst && inst.componentDidCatch) {
-		inst.componentDidCatch(err, { componentStack: '' });
+		inst.componentDidCatch(err);
 	}
 
 	expect(onError).toHaveBeenCalledTimes(1);
diff --git a/src/client/rsg-components/slots/IsolateButton.spec.tsx b/src/client/rsg-components/slots/IsolateButton.spec.tsx
index 28862a65..c530dd0c 100644
--- a/src/client/rsg-components/slots/IsolateButton.spec.tsx
+++ b/src/client/rsg-components/slots/IsolateButton.spec.tsx
@@ -1,21 +1,24 @@
 import React from 'react';
-import { shallow } from 'enzyme';
+import { createRenderer } from 'react-test-renderer/shallow';
 import IsolateButton from './IsolateButton';
 
 it('should renderer a link to isolated mode', () => {
-	const actual = shallow(<IsolateButton name="Pizza" href="/#pizza" />);
+	const renderer = createRenderer();
+	renderer.render(<IsolateButton name="Pizza" href="/#pizza" />);
 
-	expect(actual).toMatchSnapshot();
+	expect(renderer.getRenderOutput()).toMatchSnapshot();
 });
 
 it('should renderer a link to example isolated mode', () => {
-	const actual = shallow(<IsolateButton name="Pizza" href="/#pizza" example={3} />);
+	const renderer = createRenderer();
+	renderer.render(<IsolateButton name="Pizza" href="/#pizza" example={3} />);
 
-	expect(actual).toMatchSnapshot();
+	expect(renderer.getRenderOutput()).toMatchSnapshot();
 });
 
 it('should renderer a link home in isolated mode', () => {
-	const actual = shallow(<IsolateButton name="Pizza" href="/#pizza" isolated />);
+	const renderer = createRenderer();
+	renderer.render(<IsolateButton name="Pizza" href="/#pizza" isolated />);
 
-	expect(actual).toMatchSnapshot();
+	expect(renderer.getRenderOutput()).toMatchSnapshot();
 });
diff --git a/src/client/rsg-components/slots/UsageTabButton.spec.tsx b/src/client/rsg-components/slots/UsageTabButton.spec.tsx
index d4b0adac..587dd40b 100644
--- a/src/client/rsg-components/slots/UsageTabButton.spec.tsx
+++ b/src/client/rsg-components/slots/UsageTabButton.spec.tsx
@@ -1,5 +1,5 @@
 import React from 'react';
-import { shallow } from 'enzyme';
+import { createRenderer } from 'react-test-renderer/shallow';
 import UsageTabButton from './UsageTabButton';
 
 const props = {
@@ -8,13 +8,15 @@ const props = {
 };
 
 it('should renderer a button', () => {
-	const actual = shallow(<UsageTabButton {...props} props={{ props: [{ name: 'foo' }] }} />);
+	const renderer = createRenderer();
+	renderer.render(<UsageTabButton {...props} props={{ props: [{ name: 'foo' }] }} />);
 
-	expect(actual).toMatchSnapshot();
+	expect(renderer.getRenderOutput()).toMatchSnapshot();
 });
 
 it('should renderer null if there are not props or methods', () => {
-	const actual = shallow(<UsageTabButton {...props} props={{}} />);
+	const renderer = createRenderer();
+	renderer.render(<UsageTabButton {...props} props={{}} />);
 
-	expect(actual.getElement()).toBeFalsy();
+	expect(renderer.getRenderOutput()).toBe(null);
 });


Test patch:
diff --git a/src/loaders/__tests__/examples-loader.spec.ts b/src/loaders/__tests__/examples-loader.spec.ts
index 7f3ebe0b..f3710511 100644
--- a/src/loaders/__tests__/examples-loader.spec.ts
+++ b/src/loaders/__tests__/examples-loader.spec.ts
@@ -61,26 +61,9 @@ it('should replace all occurrences of __COMPONENT__ with provided query.displayN
 	);
 	expect(result).not.toMatch(/__COMPONENT__/);
 	const componentHtml = result.match(/<div>(.*?)<\/div>/);
-	expect(componentHtml && componentHtml[0]).toMatchInlineSnapshot(`
-		<div>
-		  \\n\\t
-		  <FooComponent>
-		    \\n\\t\\t
-		    <span>
-		      text
-		    </span>
-		    \\n\\t\\t
-		    <span>
-		      Name of component: FooComponent
-		    </span>
-		    \\n\\t
-		  </FooComponent>
-		  \\n\\t
-		  <FooComponent>
-		  </FooComponent>
-		  \\n
-		</div>
-	`);
+	expect(componentHtml && componentHtml[0]).toMatchInlineSnapshot(
+		`"<div>\\\\n\\\\t<FooComponent>\\\\n\\\\t\\\\t<span>text</span>\\\\n\\\\t\\\\t<span>Name of component: FooComponent</span>\\\\n\\\\t</FooComponent>\\\\n\\\\t<FooComponent />\\\\n</div>"`
+	);
 });
 
 it('should pass updateExample function from config to chunkify', () => {
diff --git a/src/loaders/utils/__tests__/__snapshots__/chunkify.spec.ts.snap b/src/loaders/utils/__tests__/__snapshots__/chunkify.spec.ts.snap
index 5dd7ea95..c51b1bd3 100644
--- a/src/loaders/utils/__tests__/__snapshots__/chunkify.spec.ts.snap
+++ b/src/loaders/utils/__tests__/__snapshots__/chunkify.spec.ts.snap
@@ -7,9 +7,7 @@ Array [
     "type": "markdown",
   },
   Object {
-    "content": <AppButton>
-  Example in vue
-</AppButton>,
+    "content": "<AppButton>Example in vue</AppButton>",
     "settings": Object {},
     "type": "code",
   },
@@ -23,18 +21,14 @@ Array [
     "type": "markdown",
   },
   Object {
-    "content": <h1>
-  Hello Markdown!
-</h1>,
+    "content": "<h1>Hello Markdown!</h1>",
     "settings": Object {
       "showcode": true,
     },
     "type": "code",
   },
   Object {
-    "content": <h1>
-  Example in frame and Without editor
-</h1>,
+    "content": "<h1>Example in frame and Without editor</h1>",
     "settings": Object {
       "frame": Object {
         "width": "400px",
@@ -47,9 +41,7 @@ Array [
     "type": "markdown",
   },
   Object {
-    "content": <h2>
-  Hello Markdown!
-</h2>,
+    "content": "<h2>Hello Markdown!</h2>",
     "settings": Object {
       "noeditor": true,
     },
@@ -71,9 +63,7 @@ Array [
     "type": "markdown",
   },
   Object {
-    "content": <AppButton>
-  Example in jsx with undefined extensions
-</AppButton>,
+    "content": "<AppButton>Example in jsx with undefined extensions</AppButton>",
     "settings": Object {},
     "type": "code",
   },
@@ -101,9 +91,7 @@ This code example should be rendered as a playground:",
     "type": "markdown",
   },
   Object {
-    "content": <h1>
-  Hello Markdown!
-</h1>,
+    "content": "<h1>Hello Markdown!</h1>",
     "settings": Object {},
     "type": "code",
   },
@@ -112,9 +100,7 @@ This code example should be rendered as a playground:",
     "type": "markdown",
   },
   Object {
-    "content": <h2>
-  Hello Markdown!
-</h2>,
+    "content": "<h2>Hello Markdown!</h2>",
     "settings": Object {},
     "type": "code",
   },
@@ -123,9 +109,7 @@ This code example should be rendered as a playground:",
     "type": "markdown",
   },
   Object {
-    "content": <h3>
-  Hello Markdown!
-</h3>,
+    "content": "<h3>Hello Markdown!</h3>",
     "settings": Object {
       "noeditor": true,
     },
diff --git a/src/loaders/utils/__tests__/__snapshots__/highlightCode.spec.ts.snap b/src/loaders/utils/__tests__/__snapshots__/highlightCode.spec.ts.snap
index 00a6fd6a..ed824d84 100644
--- a/src/loaders/utils/__tests__/__snapshots__/highlightCode.spec.ts.snap
+++ b/src/loaders/utils/__tests__/__snapshots__/highlightCode.spec.ts.snap
@@ -1,27 +1,3 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
-exports[`should highlight code with specified language 1`] = `
-<span class="token tag">
-  <span class="token tag">
-    <span class="token punctuation">
-      &lt;
-    </span>
-    p
-  </span>
-  <span class="token punctuation">
-    >
-  </span>
-</span>
-Hello React
-<span class="token tag">
-  <span class="token tag">
-    <span class="token punctuation">
-      &lt;/
-    </span>
-    p
-  </span>
-  <span class="token punctuation">
-    >
-  </span>
-</span>
-`;
+exports[`should highlight code with specified language 1`] = `"<span class=\\"token tag\\"><span class=\\"token tag\\"><span class=\\"token punctuation\\">&lt;</span>p</span><span class=\\"token punctuation\\">></span></span>Hello React<span class=\\"token tag\\"><span class=\\"token tag\\"><span class=\\"token punctuation\\">&lt;/</span>p</span><span class=\\"token punctuation\\">></span></span>"`;
diff --git a/test/deabsdeepSerializer.js b/test/deabsdeepSerializer.js
new file mode 100644
index 00000000..2b7e0742
--- /dev/null
+++ b/test/deabsdeepSerializer.js
@@ -0,0 +1,92 @@
+const escape = require('escape-string-regexp');
+const isObject = require('is-plain-obj');
+const path = require('path');
+
+const MASK = '~';
+const DIRNAME = getRootDir();
+
+/**
+ * Recursively replace absolute paths in object keys and values or in array values with a “~”.
+ *
+ * @param {object} obj
+ * @param {object} [options]
+ * @param {string} [options.root]
+ * @param {string} [options.mask]
+ * @return {object}
+ */
+function deabsDeep(obj, options) {
+	options = options || {};
+	const root = options.root || DIRNAME;
+	const mask = options.mask || MASK;
+
+	const regExp = new RegExp(escape(root), 'g');
+	const deabs = (s) => (typeof s === 'string' ? s.replace(regExp, mask) : s);
+
+	if (Array.isArray(obj)) {
+		return obj.map(deabs);
+	}
+
+	return mapObj(obj, (key, value) => [deabs(key), deabs(value)]);
+}
+
+function getRootDir(dir) {
+	dir = dir || __dirname;
+	const m = dir.match(/[\\/]node_modules[\\/]/);
+	return m ? dir.substring(0, m.index) : path.resolve(__dirname, '..');
+}
+
+/* istanbul ignore next */
+function mapObj(obj, fn, seen) {
+	seen = seen || new WeakMap();
+	if (seen.has(obj)) {
+		return seen.get(obj);
+	}
+
+	const target = {};
+
+	seen.set(obj, target);
+
+	for (const key of Object.keys(obj)) {
+		const val = obj[key];
+		const res = fn(key, val, obj);
+		let newVal = res[1];
+
+		if (isObject(newVal)) {
+			if (Array.isArray(newVal)) {
+				newVal = newVal.map((x) => (isObject(x) ? mapObj(x, fn, seen) : x));
+			} else {
+				newVal = mapObj(newVal, fn, seen);
+			}
+		}
+
+		target[res[0]] = newVal;
+	}
+
+	// The $$typeof property is a React marker that's used for serialization.
+	// deabsdeep doesn't know about React Elements but since it's registered globally,
+	// it should keep this property on the object.
+	if (obj.$$typeof) {
+		target.$$typeof = obj.$$typeof;
+	}
+
+	return target;
+}
+
+// Borrowed from https://github.com/eyolas/jest-serializer-supertest
+const KEY = '__JEST_SERIALIZER_DEABSDEEP__';
+
+module.exports = {
+	test(val) {
+		return (Array.isArray(val) || isObject(val)) && !Object.prototype.hasOwnProperty.call(val, KEY);
+	},
+	print(val, serialize) {
+		const newVal = deabsDeep(val);
+
+		// To skip maximum call stack size exceeded
+		Object.defineProperty(newVal, KEY, {
+			enumerable: false,
+		});
+
+		return serialize(newVal);
+	},
+};
diff --git a/test/jestsetup.js b/test/jestsetup.js
index aa632da4..b1b8bb3c 100644
--- a/test/jestsetup.js
+++ b/test/jestsetup.js
@@ -1,17 +1,8 @@
 /* eslint-disable no-console */
 
-import { configure, shallow, render, mount } from 'enzyme';
 import keymirror from 'keymirror';
-import Adapter from '@wojtekmaj/enzyme-adapter-react-17';
 import * as theme from '../src/client/styles/theme';
 
-configure({ adapter: new Adapter() });
-
-// Make Enzyme functions available in all test files without importing
-global.shallow = shallow;
-global.render = render;
-global.mount = mount;
-
 // Get class names from styles function
 global.classes = (styles) => keymirror(styles(theme));