File size: 1,290 Bytes
a1b6014
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import { act, type ReactNode } from 'react'
import { createRoot, type Root } from 'react-dom/client'

/** A React root in a container attached to the document, for the handful of
 *  suites that cannot use Testing Library's `render`.
 *
 *  They need the component mounted in the real document — a canvas that must
 *  paint, an element measured by its parent, a portal that reads
 *  `document.body` — and they need to unmount inside `act` mid-test to assert
 *  on teardown. Cleanup is idempotent so `afterEach` can call it after a test
 *  already did. */
export function reactRoot() {
  let root: Root | null = null
  let container: HTMLDivElement | null = null

  return {
    get container() {
      return container
    },
    /** The root itself, for a re-render that has to share an `act` with
     *  something else — a mutation-observer callback, a timer flush. */
    get root() {
      return root
    },
    render(ui: ReactNode) {
      container = document.createElement('div')
      document.body.append(container)
      root = createRoot(container)

      act(() => {
        root!.render(ui)
      })
    },
    unmount() {
      if (root) {
        act(() => root!.unmount())
      }

      container?.remove()
      root = null
      container = null
    }
  }
}