From 91726541c75cfd95db4859324bb3a9e8203d6338 Mon Sep 17 00:00:00 2001
From: Rob Snow <rsnow@adobe.com>
Date: Wed, 21 Jul 2021 16:06:31 -0700
Subject: [PATCH 01/16] Support React 18

---
 package.json    | 6 +++---
 src/dom/pure.ts | 9 +++++----
 2 files changed, 8 insertions(+), 7 deletions(-)

diff --git a/package.json b/package.json
index 9d9c0928..92dd78ee 100644
--- a/package.json
+++ b/package.json
@@ -63,9 +63,9 @@
     "eslint": "7.31.0",
     "kcd-scripts": "11.2.0",
     "prettier": "^2.2.1",
-    "react": "17.0.2",
-    "react-dom": "^17.0.1",
-    "react-test-renderer": "17.0.2",
+    "react": "next",
+    "react-dom": "next",
+    "react-test-renderer": "next",
     "ts-node": "^10.0.0",
     "typescript": "4.3.5"
   },
diff --git a/src/dom/pure.ts b/src/dom/pure.ts
index 42d66072..0f0af8eb 100644
--- a/src/dom/pure.ts
+++ b/src/dom/pure.ts
@@ -12,21 +12,22 @@ function createDomRenderer<TProps, TResult>(
 ) {
   const container = document.createElement('div')
   const testHarness = createTestHarness(rendererProps, wrapper)
-
+  // @ts-ignore
+  const root = ReactDOM.create(container);
   return {
     render(props?: TProps) {
       act(() => {
-        ReactDOM.render(testHarness(props), container)
+        root.render(testHarness(props))
       })
     },
     rerender(props?: TProps) {
       act(() => {
-        ReactDOM.render(testHarness(props), container)
+        root.render(testHarness(props))
       })
     },
     unmount() {
       act(() => {
-        ReactDOM.unmountComponentAtNode(container)
+        root.unmount()
       })
     },
     act

From 6456f4a71b4eb41bf9c40ae997c0783b5c6d8f83 Mon Sep 17 00:00:00 2001
From: Rob Snow <rsnow@adobe.com>
Date: Wed, 21 Jul 2021 16:26:56 -0700
Subject: [PATCH 02/16] fix some more obvious cases

---
 src/dom/pure.ts    | 2 +-
 src/server/pure.ts | 7 ++++---
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/src/dom/pure.ts b/src/dom/pure.ts
index 0f0af8eb..ff7a65e5 100644
--- a/src/dom/pure.ts
+++ b/src/dom/pure.ts
@@ -13,7 +13,7 @@ function createDomRenderer<TProps, TResult>(
   const container = document.createElement('div')
   const testHarness = createTestHarness(rendererProps, wrapper)
   // @ts-ignore
-  const root = ReactDOM.create(container);
+  const root = ReactDOM.createRoot(container);
   return {
     render(props?: TProps) {
       act(() => {
diff --git a/src/server/pure.ts b/src/server/pure.ts
index 1978f2d0..19e591d8 100644
--- a/src/server/pure.ts
+++ b/src/server/pure.ts
@@ -15,7 +15,8 @@ function createServerRenderer<TProps, TResult>(
   let container: HTMLDivElement | undefined
   let serverOutput: string = ''
   const testHarness = createTestHarness(rendererProps, wrapper, false)
-
+  // @ts-ignore
+  const root = ReactDOM.createRoot(container);
   return {
     render(props?: TProps) {
       renderProps = props
@@ -34,7 +35,7 @@ function createServerRenderer<TProps, TResult>(
         container = document.createElement('div')
         container.innerHTML = serverOutput
         act(() => {
-          ReactDOM.hydrate(testHarness(renderProps), container!)
+          root.hydrateRoot(testHarness(renderProps))
         })
       }
     },
@@ -43,7 +44,7 @@ function createServerRenderer<TProps, TResult>(
         throw new Error('You must hydrate the component before you can rerender')
       }
       act(() => {
-        ReactDOM.render(testHarness(props), container!)
+        root.render(testHarness(props))
       })
     },
     unmount() {

From 0d82a5f5b54799e1a79a9bbffa5ee0139ba771c9 Mon Sep 17 00:00:00 2001
From: Rob Snow <rsnow@adobe.com>
Date: Wed, 21 Jul 2021 16:53:10 -0700
Subject: [PATCH 03/16] fix hydration

---
 src/server/pure.ts | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/server/pure.ts b/src/server/pure.ts
index 19e591d8..99701c42 100644
--- a/src/server/pure.ts
+++ b/src/server/pure.ts
@@ -15,8 +15,7 @@ function createServerRenderer<TProps, TResult>(
   let container: HTMLDivElement | undefined
   let serverOutput: string = ''
   const testHarness = createTestHarness(rendererProps, wrapper, false)
-  // @ts-ignore
-  const root = ReactDOM.createRoot(container);
+  let root: any
   return {
     render(props?: TProps) {
       renderProps = props
@@ -35,7 +34,8 @@ function createServerRenderer<TProps, TResult>(
         container = document.createElement('div')
         container.innerHTML = serverOutput
         act(() => {
-          root.hydrateRoot(testHarness(renderProps))
+          // @ts-ignore
+          root = ReactDOM.hydrateRoot(container, testHarness(renderProps))
         })
       }
     },
@@ -50,7 +50,7 @@ function createServerRenderer<TProps, TResult>(
     unmount() {
       if (container) {
         act(() => {
-          ReactDOM.unmountComponentAtNode(container!)
+          root.unmount()
         })
       }
     },

From 81db73a77d463c52f23131bd580d4a8390d5d021 Mon Sep 17 00:00:00 2001
From: Rob Snow <rsnow@adobe.com>
Date: Wed, 21 Jul 2021 17:17:02 -0700
Subject: [PATCH 04/16] annotate a test so I can get help

---
 src/__tests__/resultHistory.test.ts | 3 ++-
 src/dom/pure.ts                     | 2 +-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/src/__tests__/resultHistory.test.ts b/src/__tests__/resultHistory.test.ts
index edb8837f..ca18e825 100644
--- a/src/__tests__/resultHistory.test.ts
+++ b/src/__tests__/resultHistory.test.ts
@@ -23,7 +23,8 @@ describe('result history tests', () => {
       rerender(2)
 
       expect(result.error).toEqual(Error('expected'))
-      expect(result.all).toEqual([0, 1, Error('expected')])
+      // double error thrown for dom, but not default or native...
+      expect(result.all).toEqual([0, 1, Error('expected'), Error('expected')])
 
       rerender(3)
 
diff --git a/src/dom/pure.ts b/src/dom/pure.ts
index ff7a65e5..162e23c0 100644
--- a/src/dom/pure.ts
+++ b/src/dom/pure.ts
@@ -13,7 +13,7 @@ function createDomRenderer<TProps, TResult>(
   const container = document.createElement('div')
   const testHarness = createTestHarness(rendererProps, wrapper)
   // @ts-ignore
-  const root = ReactDOM.createRoot(container);
+  const root = ReactDOM.createRoot(container)
   return {
     render(props?: TProps) {
       act(() => {

From 1f0bf1db4e6b61e7fae79822aa341784478c047a Mon Sep 17 00:00:00 2001
From: Rob Snow <rsnow@adobe.com>
Date: Thu, 22 Jul 2021 18:12:23 -0700
Subject: [PATCH 05/16] Will definitely need something like this in order to
 support 17 and 18 at once

---
 src/dom/pure.ts | 60 ++++++++++++++++++++++++++++++++++---------------
 1 file changed, 42 insertions(+), 18 deletions(-)

diff --git a/src/dom/pure.ts b/src/dom/pure.ts
index 162e23c0..cbab3e8a 100644
--- a/src/dom/pure.ts
+++ b/src/dom/pure.ts
@@ -6,6 +6,8 @@ import { RendererProps, RendererOptions } from '../types/react'
 import { createRenderHook } from '../core'
 import { createTestHarness } from '../helpers/createTestHarness'
 
+const isReactConcurrent = !!ReactDOM.createRoot;
+
 function createDomRenderer<TProps, TResult>(
   rendererProps: RendererProps<TProps, TResult>,
   { wrapper }: RendererOptions<TProps>
@@ -13,24 +15,46 @@ function createDomRenderer<TProps, TResult>(
   const container = document.createElement('div')
   const testHarness = createTestHarness(rendererProps, wrapper)
   // @ts-ignore
-  const root = ReactDOM.createRoot(container)
-  return {
-    render(props?: TProps) {
-      act(() => {
-        root.render(testHarness(props))
-      })
-    },
-    rerender(props?: TProps) {
-      act(() => {
-        root.render(testHarness(props))
-      })
-    },
-    unmount() {
-      act(() => {
-        root.unmount()
-      })
-    },
-    act
+  if (isReactConcurrent) {
+    // @ts-ignore
+    const root = ReactDOM.createRoot(container)
+    return {
+      render(props?: TProps) {
+        act(() => {
+          root.render(testHarness(props))
+        })
+      },
+      rerender(props?: TProps) {
+        act(() => {
+          root.render(testHarness(props))
+        })
+      },
+      unmount() {
+        act(() => {
+          root.unmount()
+        })
+      },
+      act
+    }
+  } else {
+    return {
+      render(props?: TProps) {
+        act(() => {
+          ReactDOM.render(testHarness(props), container)
+        })
+      },
+      rerender(props?: TProps) {
+        act(() => {
+          ReactDOM.render(testHarness(props), container)
+        })
+      },
+      unmount() {
+        act(() => {
+          ReactDOM.unmountComponentAtNode(container)
+        })
+      },
+      act
+    }
   }
 }
 

From 3cc6f2ee871e971108a38aa632f3ae1eba2502c8 Mon Sep 17 00:00:00 2001
From: Rob Snow <rsnow@adobe.com>
Date: Fri, 23 Jul 2021 13:18:34 -0700
Subject: [PATCH 06/16] drop prepare run tests against all supported major
 react versions support both versions  and fix ts

---
 .github/workflows/validate.yml |   4 ++
 package.json                   |   1 -
 src/dom/pure.ts                |   2 +-
 src/server/pure.ts             | 115 +++++++++++++++++++++++----------
 4 files changed, 85 insertions(+), 37 deletions(-)

diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml
index b121fcd4..749f27b5 100644
--- a/.github/workflows/validate.yml
+++ b/.github/workflows/validate.yml
@@ -17,6 +17,7 @@ jobs:
     strategy:
       matrix:
         node: [12.13, 12, 14, 16]
+        react: [16, 17, next]
     runs-on: ubuntu-latest
     steps:
       - name: 🛑 Cancel Previous Runs
@@ -37,6 +38,9 @@ jobs:
         env:
           HUSKY_SKIP_INSTALL: true
 
+      - name: Use React version
+        run: npm install --save-dev react@${{ matrix.react }} react-dom@${{ matrix.react }} react-test-renderer@${{ matrix.react }}
+
       - name: ▶️ Run validate script
         run: npm run validate
 
diff --git a/package.json b/package.json
index 92dd78ee..9b44da7c 100644
--- a/package.json
+++ b/package.json
@@ -33,7 +33,6 @@
   "scripts": {
     "setup": "npm install && npm run validate -s",
     "validate": "kcd-scripts validate",
-    "prepare": "npm run build",
     "build": "kcd-scripts build --out-dir lib && npm run generate:submodules",
     "generate:submodules": "ts-node scripts/generate-submodules.ts",
     "test": "kcd-scripts test",
diff --git a/src/dom/pure.ts b/src/dom/pure.ts
index cbab3e8a..2e060b73 100644
--- a/src/dom/pure.ts
+++ b/src/dom/pure.ts
@@ -6,6 +6,7 @@ import { RendererProps, RendererOptions } from '../types/react'
 import { createRenderHook } from '../core'
 import { createTestHarness } from '../helpers/createTestHarness'
 
+// @ts-ignore
 const isReactConcurrent = !!ReactDOM.createRoot;
 
 function createDomRenderer<TProps, TResult>(
@@ -14,7 +15,6 @@ function createDomRenderer<TProps, TResult>(
 ) {
   const container = document.createElement('div')
   const testHarness = createTestHarness(rendererProps, wrapper)
-  // @ts-ignore
   if (isReactConcurrent) {
     // @ts-ignore
     const root = ReactDOM.createRoot(container)
diff --git a/src/server/pure.ts b/src/server/pure.ts
index 99701c42..355399fa 100644
--- a/src/server/pure.ts
+++ b/src/server/pure.ts
@@ -7,6 +7,9 @@ import { RendererOptions, RendererProps } from '../types/react'
 import { createRenderHook } from '../core'
 import { createTestHarness } from '../helpers/createTestHarness'
 
+// @ts-ignore
+const isReactConcurrent = !!ReactDOM.createRoot;
+
 function createServerRenderer<TProps, TResult>(
   rendererProps: RendererProps<TProps, TResult>,
   { wrapper }: RendererOptions<TProps>
@@ -15,46 +18,88 @@ function createServerRenderer<TProps, TResult>(
   let container: HTMLDivElement | undefined
   let serverOutput: string = ''
   const testHarness = createTestHarness(rendererProps, wrapper, false)
-  let root: any
-  return {
-    render(props?: TProps) {
-      renderProps = props
-      act(() => {
-        try {
-          serverOutput = ReactDOMServer.renderToString(testHarness(props))
-        } catch (e: unknown) {
-          rendererProps.setError(e as Error)
+  if (isReactConcurrent) {
+    let root: any
+    return {
+      render(props?: TProps) {
+        renderProps = props
+        act(() => {
+          try {
+            serverOutput = ReactDOMServer.renderToString(testHarness(props))
+          } catch (e: unknown) {
+            rendererProps.setError(e as Error)
+          }
+        })
+      },
+      hydrate() {
+        if (container) {
+          throw new Error('The component can only be hydrated once')
+        } else {
+          container = document.createElement('div')
+          container.innerHTML = serverOutput
+          act(() => {
+            // @ts-ignore
+            root = ReactDOM.hydrateRoot(container, testHarness(renderProps))
+          })
+        }
+      },
+      rerender(props?: TProps) {
+        if (!container) {
+          throw new Error('You must hydrate the component before you can rerender')
+        }
+        act(() => {
+          root.render(testHarness(props))
+        })
+      },
+      unmount() {
+        if (container) {
+          act(() => {
+            root.unmount()
+          })
         }
-      })
-    },
-    hydrate() {
-      if (container) {
-        throw new Error('The component can only be hydrated once')
-      } else {
-        container = document.createElement('div')
-        container.innerHTML = serverOutput
+      },
+      act
+    };
+  } else {
+    return {
+      render(props?: TProps) {
+        renderProps = props
         act(() => {
-          // @ts-ignore
-          root = ReactDOM.hydrateRoot(container, testHarness(renderProps))
+          try {
+            serverOutput = ReactDOMServer.renderToString(testHarness(props))
+          } catch (e: unknown) {
+            rendererProps.setError(e as Error)
+          }
         })
-      }
-    },
-    rerender(props?: TProps) {
-      if (!container) {
-        throw new Error('You must hydrate the component before you can rerender')
-      }
-      act(() => {
-        root.render(testHarness(props))
-      })
-    },
-    unmount() {
-      if (container) {
+      },
+      hydrate() {
+        if (container) {
+          throw new Error('The component can only be hydrated once')
+        } else {
+          container = document.createElement('div')
+          container.innerHTML = serverOutput
+          act(() => {
+            ReactDOM.hydrate(testHarness(renderProps), container!)
+          })
+        }
+      },
+      rerender(props?: TProps) {
+        if (!container) {
+          throw new Error('You must hydrate the component before you can rerender')
+        }
         act(() => {
-          root.unmount()
+          ReactDOM.render(testHarness(props), container!)
         })
-      }
-    },
-    act
+      },
+      unmount() {
+        if (container) {
+          act(() => {
+            ReactDOM.unmountComponentAtNode(container!)
+          })
+        }
+      },
+      act
+    };
   }
 }
 

From 15347e55514cdaa1175cdd58f9659bd291427244 Mon Sep 17 00:00:00 2001
From: Rob Snow <rsnow@adobe.com>
Date: Fri, 23 Jul 2021 13:26:25 -0700
Subject: [PATCH 07/16] restore package.json fix test matrix to choose
 appropriate react versions

---
 .github/workflows/validate.yml | 2 +-
 package.json                   | 6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml
index 749f27b5..51a1f1f7 100644
--- a/.github/workflows/validate.yml
+++ b/.github/workflows/validate.yml
@@ -17,7 +17,7 @@ jobs:
     strategy:
       matrix:
         node: [12.13, 12, 14, 16]
-        react: [16, 17, next]
+        react: [^16.9.0, ^17.0.2, next]
     runs-on: ubuntu-latest
     steps:
       - name: 🛑 Cancel Previous Runs
diff --git a/package.json b/package.json
index 9b44da7c..91040398 100644
--- a/package.json
+++ b/package.json
@@ -62,9 +62,9 @@
     "eslint": "7.31.0",
     "kcd-scripts": "11.2.0",
     "prettier": "^2.2.1",
-    "react": "next",
-    "react-dom": "next",
-    "react-test-renderer": "next",
+    "react": "17.0.2",
+    "react-dom": "17.0.2",
+    "react-test-renderer": "17.0.2",
     "ts-node": "^10.0.0",
     "typescript": "4.3.5"
   },

From 25cfd74c79881b90d25492334d5b1df08c510e48 Mon Sep 17 00:00:00 2001
From: Rob Snow <rsnow@adobe.com>
Date: Fri, 23 Jul 2021 13:30:42 -0700
Subject: [PATCH 08/16] restore test to passing but leave comment about 18

---
 src/__tests__/resultHistory.test.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/__tests__/resultHistory.test.ts b/src/__tests__/resultHistory.test.ts
index ca18e825..9faf9d52 100644
--- a/src/__tests__/resultHistory.test.ts
+++ b/src/__tests__/resultHistory.test.ts
@@ -24,7 +24,7 @@ describe('result history tests', () => {
 
       expect(result.error).toEqual(Error('expected'))
       // double error thrown for dom, but not default or native...
-      expect(result.all).toEqual([0, 1, Error('expected'), Error('expected')])
+      expect(result.all).toEqual([0, 1, Error('expected')])
 
       rerender(3)
 

From 668088b801cefdb123d310656e35bff3f7bf1b37 Mon Sep 17 00:00:00 2001
From: Rob Snow <rsnow@adobe.com>
Date: Fri, 23 Jul 2021 13:38:08 -0700
Subject: [PATCH 09/16] Fix install script one last time

---
 .github/workflows/validate.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml
index 51a1f1f7..18ec4c9f 100644
--- a/.github/workflows/validate.yml
+++ b/.github/workflows/validate.yml
@@ -39,7 +39,7 @@ jobs:
           HUSKY_SKIP_INSTALL: true
 
       - name: Use React version
-        run: npm install --save-dev react@${{ matrix.react }} react-dom@${{ matrix.react }} react-test-renderer@${{ matrix.react }}
+        run: npm install --save-dev react@"${{ matrix.react }}" react-dom@"${{ matrix.react }}" react-test-renderer@"${{ matrix.react }}"
 
       - name: ▶️ Run validate script
         run: npm run validate

From 8fa0041519f710190ae79607905fdb82088dea11 Mon Sep 17 00:00:00 2001
From: Rob Snow <rsnow@adobe.com>
Date: Fri, 23 Jul 2021 13:43:00 -0700
Subject: [PATCH 10/16] add some shortcut scripts so it's easier to test
 locally

---
 package.json | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/package.json b/package.json
index 91040398..d8862090 100644
--- a/package.json
+++ b/package.json
@@ -42,7 +42,9 @@
     "coverage": "codecov",
     "docs:dev": "docz dev",
     "docs:build": "docz build",
-    "contributors:add": "all-contributors add"
+    "contributors:add": "all-contributors add",
+    "install-16": "npm install --save-dev react@\"^16.9.0\" react-dom@\"^16.9.0\" react-test-renderer@\"^16.9.0\"",
+    "install-next": "npm install --save-dev react@next react-dom@next react-test-renderer@next",
   },
   "dependencies": {
     "@babel/runtime": "^7.12.5",

From c95ef457787ace7bf5937294619b8db55dd06122 Mon Sep 17 00:00:00 2001
From: Rob Snow <rsnow@adobe.com>
Date: Fri, 23 Jul 2021 15:03:02 -0700
Subject: [PATCH 11/16] remove invalid comma

---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/package.json b/package.json
index d8862090..3a5983e9 100644
--- a/package.json
+++ b/package.json
@@ -44,7 +44,7 @@
     "docs:build": "docz build",
     "contributors:add": "all-contributors add",
     "install-16": "npm install --save-dev react@\"^16.9.0\" react-dom@\"^16.9.0\" react-test-renderer@\"^16.9.0\"",
-    "install-next": "npm install --save-dev react@next react-dom@next react-test-renderer@next",
+    "install-next": "npm install --save-dev react@next react-dom@next react-test-renderer@next"
   },
   "dependencies": {
     "@babel/runtime": "^7.12.5",

From 00526a84940cbc64341018888e4d5b123b31d21f Mon Sep 17 00:00:00 2001
From: Rob Snow <rsnow@adobe.com>
Date: Fri, 23 Jul 2021 15:46:39 -0700
Subject: [PATCH 12/16] add support for the minimum specified supported version
 as well as latest of all majors after

---
 .github/workflows/validate.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml
index 18ec4c9f..0d697b05 100644
--- a/.github/workflows/validate.yml
+++ b/.github/workflows/validate.yml
@@ -17,7 +17,7 @@ jobs:
     strategy:
       matrix:
         node: [12.13, 12, 14, 16]
-        react: [^16.9.0, ^17.0.2, next]
+        react: [16.9.0, ^16, ^17, next]
     runs-on: ubuntu-latest
     steps:
       - name: 🛑 Cancel Previous Runs

From c060620d90391ae009e4c10c3e9dbb9ef9be7514 Mon Sep 17 00:00:00 2001
From: Rob Snow <rsnow@adobe.com>
Date: Fri, 23 Jul 2021 16:17:04 -0700
Subject: [PATCH 13/16] temporarily drop coverageThreshold

---
 jest.config.js | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/jest.config.js b/jest.config.js
index 66b8064e..9abc92d8 100644
--- a/jest.config.js
+++ b/jest.config.js
@@ -1,4 +1,12 @@
 const { jest: jestConfig } = require('kcd-scripts/config')
+jestConfig.coverageThreshold = {
+  global: {
+    branches: 80,
+    functions: 80,
+    lines: 80,
+    statements: 80
+  }
+}
 module.exports = Object.assign(jestConfig, {
   setupFiles: ['<rootDir>/src/__tests__/utils/runForRenderers.ts']
 })

From d4ba70ce2ca27465af0660b546be108abddecf23 Mon Sep 17 00:00:00 2001
From: Rob Snow <rsnow@adobe.com>
Date: Fri, 23 Jul 2021 16:55:33 -0700
Subject: [PATCH 14/16] experimental tests should not block known quantities

---
 .github/workflows/validate.yml | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml
index 0d697b05..c0a40890 100644
--- a/.github/workflows/validate.yml
+++ b/.github/workflows/validate.yml
@@ -14,10 +14,12 @@ jobs:
   main:
     # ignore all-contributors PRs
     if: ${{ !contains(github.head_ref, 'all-contributors') }}
+    continue-on-error: ${{ contains(matrix.react, 'next') }}
     strategy:
       matrix:
         node: [12.13, 12, 14, 16]
         react: [16.9.0, ^16, ^17, next]
+
     runs-on: ubuntu-latest
     steps:
       - name: 🛑 Cancel Previous Runs

From 2b4a770545561534eeff697a72dd44b0de4ebeda Mon Sep 17 00:00:00 2001
From: Michael Peyper <mpeyper7@gmail.com>
Date: Sat, 24 Jul 2021 22:20:07 +1000
Subject: [PATCH 15/16] refactor: add createLegacyRoot to reduce uncovered code
 percentage

Ignore root creation code from code covereage
Introduced next react types for React.Root
---
 src/dom/pure.ts           |  63 +++++++--------------
 src/helpers/createRoot.ts |  30 ++++++++++
 src/server/pure.ts        | 114 ++++++++++++--------------------------
 tsconfig.json             |   3 +-
 4 files changed, 85 insertions(+), 125 deletions(-)
 create mode 100644 src/helpers/createRoot.ts

diff --git a/src/dom/pure.ts b/src/dom/pure.ts
index 2e060b73..e0759f1d 100644
--- a/src/dom/pure.ts
+++ b/src/dom/pure.ts
@@ -1,13 +1,10 @@
-import * as ReactDOM from 'react-dom'
 import { act } from 'react-dom/test-utils'
 
 import { RendererProps, RendererOptions } from '../types/react'
 
 import { createRenderHook } from '../core'
 import { createTestHarness } from '../helpers/createTestHarness'
-
-// @ts-ignore
-const isReactConcurrent = !!ReactDOM.createRoot;
+import { createRoot } from '../helpers/createRoot'
 
 function createDomRenderer<TProps, TResult>(
   rendererProps: RendererProps<TProps, TResult>,
@@ -15,46 +12,24 @@ function createDomRenderer<TProps, TResult>(
 ) {
   const container = document.createElement('div')
   const testHarness = createTestHarness(rendererProps, wrapper)
-  if (isReactConcurrent) {
-    // @ts-ignore
-    const root = ReactDOM.createRoot(container)
-    return {
-      render(props?: TProps) {
-        act(() => {
-          root.render(testHarness(props))
-        })
-      },
-      rerender(props?: TProps) {
-        act(() => {
-          root.render(testHarness(props))
-        })
-      },
-      unmount() {
-        act(() => {
-          root.unmount()
-        })
-      },
-      act
-    }
-  } else {
-    return {
-      render(props?: TProps) {
-        act(() => {
-          ReactDOM.render(testHarness(props), container)
-        })
-      },
-      rerender(props?: TProps) {
-        act(() => {
-          ReactDOM.render(testHarness(props), container)
-        })
-      },
-      unmount() {
-        act(() => {
-          ReactDOM.unmountComponentAtNode(container)
-        })
-      },
-      act
-    }
+  const root = createRoot(container)
+  return {
+    render(props?: TProps) {
+      act(() => {
+        root.render(testHarness(props))
+      })
+    },
+    rerender(props?: TProps) {
+      act(() => {
+        root.render(testHarness(props))
+      })
+    },
+    unmount() {
+      act(() => {
+        root.unmount()
+      })
+    },
+    act
   }
 }
 
diff --git a/src/helpers/createRoot.ts b/src/helpers/createRoot.ts
new file mode 100644
index 00000000..bd6a0175
--- /dev/null
+++ b/src/helpers/createRoot.ts
@@ -0,0 +1,30 @@
+import * as ReactDOM from 'react-dom'
+import * as React from 'react'
+
+/* istanbul ignore next */
+function createLegacyRoot(container: Element): ReactDOM.Root {
+  return {
+    render(element: React.ReactElement) {
+      ReactDOM.render(element, container)
+    },
+    unmount() {
+      ReactDOM.unmountComponentAtNode(container)
+    }
+  }
+}
+
+/* istanbul ignore next */
+export function createRoot(container: Element) {
+  return (ReactDOM.createRoot ? ReactDOM.createRoot : createLegacyRoot)(container)
+}
+
+/* istanbul ignore next */
+export function hydrateLegacyRoot(container: Element, element: React.ReactElement): ReactDOM.Root {
+  ReactDOM.hydrate(element, container)
+  return createLegacyRoot(container)
+}
+
+/* istanbul ignore next */
+export function hydrateRoot(container: Element, element: React.ReactElement) {
+  return (ReactDOM.hydrateRoot ? ReactDOM.hydrateRoot : hydrateLegacyRoot)(container, element)
+}
diff --git a/src/server/pure.ts b/src/server/pure.ts
index 355399fa..10696bb5 100644
--- a/src/server/pure.ts
+++ b/src/server/pure.ts
@@ -6,100 +6,54 @@ import { RendererOptions, RendererProps } from '../types/react'
 
 import { createRenderHook } from '../core'
 import { createTestHarness } from '../helpers/createTestHarness'
-
-// @ts-ignore
-const isReactConcurrent = !!ReactDOM.createRoot;
+import { hydrateRoot } from '../helpers/createRoot'
 
 function createServerRenderer<TProps, TResult>(
   rendererProps: RendererProps<TProps, TResult>,
   { wrapper }: RendererOptions<TProps>
 ) {
   let renderProps: TProps | undefined
-  let container: HTMLDivElement | undefined
   let serverOutput: string = ''
   const testHarness = createTestHarness(rendererProps, wrapper, false)
-  if (isReactConcurrent) {
-    let root: any
-    return {
-      render(props?: TProps) {
-        renderProps = props
-        act(() => {
-          try {
-            serverOutput = ReactDOMServer.renderToString(testHarness(props))
-          } catch (e: unknown) {
-            rendererProps.setError(e as Error)
-          }
-        })
-      },
-      hydrate() {
-        if (container) {
-          throw new Error('The component can only be hydrated once')
-        } else {
-          container = document.createElement('div')
-          container.innerHTML = serverOutput
-          act(() => {
-            // @ts-ignore
-            root = ReactDOM.hydrateRoot(container, testHarness(renderProps))
-          })
-        }
-      },
-      rerender(props?: TProps) {
-        if (!container) {
-          throw new Error('You must hydrate the component before you can rerender')
+  let root: ReactDOM.Root | undefined
+  return {
+    render(props?: TProps) {
+      renderProps = props
+      act(() => {
+        try {
+          serverOutput = ReactDOMServer.renderToString(testHarness(props))
+        } catch (e: unknown) {
+          rendererProps.setError(e as Error)
         }
+      })
+    },
+    hydrate() {
+      if (root) {
+        throw new Error('The component can only be hydrated once')
+      } else {
+        const container = document.createElement('div')
+        container.innerHTML = serverOutput
         act(() => {
-          root.render(testHarness(props))
+          root = hydrateRoot(container, testHarness(renderProps))
         })
-      },
-      unmount() {
-        if (container) {
-          act(() => {
-            root.unmount()
-          })
-        }
-      },
-      act
-    };
-  } else {
-    return {
-      render(props?: TProps) {
-        renderProps = props
-        act(() => {
-          try {
-            serverOutput = ReactDOMServer.renderToString(testHarness(props))
-          } catch (e: unknown) {
-            rendererProps.setError(e as Error)
-          }
-        })
-      },
-      hydrate() {
-        if (container) {
-          throw new Error('The component can only be hydrated once')
-        } else {
-          container = document.createElement('div')
-          container.innerHTML = serverOutput
-          act(() => {
-            ReactDOM.hydrate(testHarness(renderProps), container!)
-          })
-        }
-      },
-      rerender(props?: TProps) {
-        if (!container) {
+      }
+    },
+    rerender(props?: TProps) {
+      act(() => {
+        if (!root) {
           throw new Error('You must hydrate the component before you can rerender')
         }
-        act(() => {
-          ReactDOM.render(testHarness(props), container!)
-        })
-      },
-      unmount() {
-        if (container) {
-          act(() => {
-            ReactDOM.unmountComponentAtNode(container!)
-          })
+        root.render(testHarness(props))
+      })
+    },
+    unmount() {
+      act(() => {
+        if (root) {
+          root.unmount()
         }
-      },
-      act
-    };
+      })
+    },
+    act
   }
 }
 
diff --git a/tsconfig.json b/tsconfig.json
index 7661340c..08ca21c1 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,6 +1,7 @@
 {
   "extends": "./node_modules/kcd-scripts/shared-tsconfig.json",
   "compilerOptions": {
-    "target": "ES6"
+    "target": "ES6",
+    "types": ["node", "jest", "react/next", "react-dom/next"]
   }
 }

From ea9d4f9ed857ef33a57f81f3510ce7ae4789db4c Mon Sep 17 00:00:00 2001
From: Michael Peyper <mpeyper7@gmail.com>
Date: Sat, 24 Jul 2021 22:27:52 +1000
Subject: [PATCH 16/16] chore: increase coverage threshold again

---
 jest.config.js | 8 --------
 1 file changed, 8 deletions(-)

diff --git a/jest.config.js b/jest.config.js
index 9abc92d8..66b8064e 100644
--- a/jest.config.js
+++ b/jest.config.js
@@ -1,12 +1,4 @@
 const { jest: jestConfig } = require('kcd-scripts/config')
-jestConfig.coverageThreshold = {
-  global: {
-    branches: 80,
-    functions: 80,
-    lines: 80,
-    statements: 80
-  }
-}
 module.exports = Object.assign(jestConfig, {
   setupFiles: ['<rootDir>/src/__tests__/utils/runForRenderers.ts']
 })