Skip to content

Commit

Permalink
Remove support for legacy root
Browse files Browse the repository at this point in the history
  • Loading branch information
Sebastian Silbermann committed Jan 30, 2024
1 parent aabdfda commit 1a3e987
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 110 deletions.
25 changes: 0 additions & 25 deletions src/__tests__/render.js
Original file line number Diff line number Diff line change
Expand Up @@ -212,29 +212,4 @@ describe('render API', () => {

expect(wrapperComponentMountEffect).toHaveBeenCalledTimes(1)
})

test('legacyRoot uses legacy ReactDOM.render', () => {
expect(() => {
render(<div />, {legacyRoot: true})
}).toErrorDev(
[
"Warning: ReactDOM.render is no longer supported in React 18. Use createRoot instead. Until you switch to the new API, your app will behave as if it's running React 17. Learn more: https://reactjs.org/link/switch-to-createroot",
],
{withoutStack: true},
)
})

test('legacyRoot uses legacy ReactDOM.hydrate', () => {
const ui = <div />
const container = document.createElement('div')
container.innerHTML = ReactDOMServer.renderToString(ui)
expect(() => {
render(ui, {container, hydrate: true, legacyRoot: true})
}).toErrorDev(
[
"Warning: ReactDOM.hydrate is no longer supported in React 18. Use hydrateRoot instead. Until you switch to the new API, your app will behave as if it's running React 17. Learn more: https://reactjs.org/link/switch-to-createroot",
],
{withoutStack: true},
)
})
})
102 changes: 24 additions & 78 deletions src/pure.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import * as React from 'react'
import ReactDOM from 'react-dom'
import * as ReactDOMClient from 'react-dom/client'
import {
getQueriesForElement,
Expand Down Expand Up @@ -73,7 +72,7 @@ configureDTL({
*/
const mountedContainers = new Set()
/**
* @type Array<{container: import('react-dom').Container, root: ReturnType<typeof createConcurrentRoot>}>
* @type Array<{container: import('react-dom').Container, root: ReturnType<typeof createTestRoot>}>
*/
const mountedRootEntries = []

Expand All @@ -89,73 +88,10 @@ function wrapUiIfNeeded(innerElement, wrapperComponent) {
: innerElement
}

function createConcurrentRoot(
container,
{hydrate, ui, wrapper: WrapperComponent},
) {
let root
if (hydrate) {
act(() => {
root = ReactDOMClient.hydrateRoot(
container,
strictModeIfNeeded(wrapUiIfNeeded(ui, WrapperComponent)),
)
})
} else {
root = ReactDOMClient.createRoot(container)
}

return {
hydrate() {
/* istanbul ignore if */
if (!hydrate) {
throw new Error(
'Attempted to hydrate a non-hydrateable root. This is a bug in `@testing-library/react`.',
)
}
// Nothing to do since hydration happens when creating the root object.
},
render(element) {
root.render(element)
},
unmount() {
root.unmount()
},
}
}

function createLegacyRoot(container) {
return {
hydrate(element) {
ReactDOM.hydrate(element, container)
},
render(element) {
ReactDOM.render(element, container)
},
unmount() {
ReactDOM.unmountComponentAtNode(container)
},
}
}

function renderRoot(
function createTestView(
ui,
{baseElement, container, hydrate, queries, root, wrapper: WrapperComponent},
) {
act(() => {
if (hydrate) {
root.hydrate(
strictModeIfNeeded(wrapUiIfNeeded(ui, WrapperComponent)),
container,
)
} else {
root.render(
strictModeIfNeeded(wrapUiIfNeeded(ui, WrapperComponent)),
container,
)
}
})

return {
container,
baseElement,
Expand All @@ -171,7 +107,7 @@ function renderRoot(
})
},
rerender: rerenderUi => {
renderRoot(rerenderUi, {
createTestView(rerenderUi, {
container,
baseElement,
root,
Expand All @@ -198,14 +134,7 @@ function renderRoot(

function render(
ui,
{
container,
baseElement = container,
legacyRoot = false,
queries,
hydrate = false,
wrapper,
} = {},
{container, baseElement = container, queries, hydrate = false, wrapper} = {},
) {
if (!baseElement) {
// default to document.body instead of documentElement to avoid output of potentially-large
Expand All @@ -219,8 +148,16 @@ function render(
let root
// eslint-disable-next-line no-negated-condition -- we want to map the evolution of this over time. The root is created first. Only later is it re-used so we don't want to read the case that happens later first.
if (!mountedContainers.has(container)) {
const createRootImpl = legacyRoot ? createLegacyRoot : createConcurrentRoot
root = createRootImpl(container, {hydrate, ui, wrapper})
if (hydrate) {
act(() => {
root = ReactDOMClient.hydrateRoot(
container,
strictModeIfNeeded(wrapUiIfNeeded(ui, WrapperComponent)),
)
})
} else {
root = ReactDOMClient.createRoot(container)
}

mountedRootEntries.push({container, root})
// we'll add it to the mounted containers regardless of whether it's actually
Expand All @@ -238,7 +175,16 @@ function render(
})
}

return renderRoot(ui, {
if (!hydrate) {
act(() => {
root.render(
strictModeIfNeeded(wrapUiIfNeeded(ui, WrapperComponent)),
container,
)
})
}

return createTestView(ui, {
container,
baseElement,
queries,
Expand Down
9 changes: 2 additions & 7 deletions types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,17 +67,12 @@ export interface RenderOptions<
*/
baseElement?: BaseElement
/**
* If `hydrate` is set to `true`, then it will render with `ReactDOM.hydrate`. This may be useful if you are using server-side
* rendering and use ReactDOM.hydrate to mount your components.
* If `hydrate` is set to `true`, then it will create a root with `ReactDOMClient.hydrateRoot`. This may be useful if you are using server-side
* rendering and use ReactDOMClient.hydrateRoot to mount your components.
*
* @see https://testing-library.com/docs/react-testing-library/api/#hydrate)
*/
hydrate?: boolean
/**
* Set to `true` if you want to force synchronous `ReactDOM.render`.
* Otherwise `render` will default to concurrent React if available.
*/
legacyRoot?: boolean
/**
* Queries to bind. Overrides the default set from DOM Testing Library unless merged.
*
Expand Down

0 comments on commit 1a3e987

Please sign in to comment.