diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 50d61077..6510d819 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] + react: [16.9.0, ^16, ^17, next] + runs-on: ubuntu-latest steps: - name: 🛑 Cancel Previous Runs diff --git a/src/__tests__/resultHistory.test.ts b/src/__tests__/resultHistory.test.ts index edb8837f..9faf9d52 100644 --- a/src/__tests__/resultHistory.test.ts +++ b/src/__tests__/resultHistory.test.ts @@ -23,6 +23,7 @@ describe('result history tests', () => { rerender(2) expect(result.error).toEqual(Error('expected')) + // double error thrown for dom, but not default or native... expect(result.all).toEqual([0, 1, Error('expected')]) rerender(3) diff --git a/src/dom/pure.ts b/src/dom/pure.ts index 42d66072..e0759f1d 100644 --- a/src/dom/pure.ts +++ b/src/dom/pure.ts @@ -1,10 +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' +import { createRoot } from '../helpers/createRoot' function createDomRenderer( rendererProps: RendererProps, @@ -12,21 +12,21 @@ function createDomRenderer( ) { const container = document.createElement('div') const testHarness = createTestHarness(rendererProps, wrapper) - + const root = createRoot(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 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 1978f2d0..10696bb5 100644 --- a/src/server/pure.ts +++ b/src/server/pure.ts @@ -6,16 +6,16 @@ import { RendererOptions, RendererProps } from '../types/react' import { createRenderHook } from '../core' import { createTestHarness } from '../helpers/createTestHarness' +import { hydrateRoot } from '../helpers/createRoot' function createServerRenderer( rendererProps: RendererProps, { wrapper }: RendererOptions ) { let renderProps: TProps | undefined - let container: HTMLDivElement | undefined let serverOutput: string = '' const testHarness = createTestHarness(rendererProps, wrapper, false) - + let root: ReactDOM.Root | undefined return { render(props?: TProps) { renderProps = props @@ -28,30 +28,30 @@ function createServerRenderer( }) }, hydrate() { - if (container) { + if (root) { throw new Error('The component can only be hydrated once') } else { - container = document.createElement('div') + const container = document.createElement('div') container.innerHTML = serverOutput act(() => { - ReactDOM.hydrate(testHarness(renderProps), container!) + root = hydrateRoot(container, testHarness(renderProps)) }) } }, rerender(props?: TProps) { - if (!container) { - throw new Error('You must hydrate the component before you can rerender') - } act(() => { - ReactDOM.render(testHarness(props), container!) + if (!root) { + throw new Error('You must hydrate the component before you can rerender') + } + root.render(testHarness(props)) }) }, unmount() { - if (container) { - act(() => { - ReactDOM.unmountComponentAtNode(container!) - }) - } + act(() => { + if (root) { + root.unmount() + } + }) }, 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"] } }