diff --git a/.changeset/empty-spiders-grow.md b/.changeset/empty-spiders-grow.md new file mode 100644 index 0000000000..9017386841 --- /dev/null +++ b/.changeset/empty-spiders-grow.md @@ -0,0 +1,5 @@ +--- +'@shopify/react-testing': major +--- + +Remove React 17 compatability diff --git a/packages/react-testing/src/compat.ts b/packages/react-testing/src/compat.ts index dc369ba309..e0bf789095 100644 --- a/packages/react-testing/src/compat.ts +++ b/packages/react-testing/src/compat.ts @@ -1,46 +1,5 @@ -import ReactDOM from 'react-dom'; -import React from 'react'; -import type {Root as ReactRoot} from 'react-dom/client'; import {act as oldAct} from 'react-dom/test-utils'; -import type {ReactInstance, Fiber} from './types'; - -export function getInternals(instance: ReactInstance): Fiber { - // In React 17+ _reactInternalFiber was renamed to _reactInternals. As such we need to handle both APIs to maintain support. - - if ('_reactInternalFiber' in instance) { - return instance._reactInternalFiber; - } - - return instance._reactInternals; -} - -/** Shim to provide createRoot backwards compatibility for React < 18 */ -function createRootShim(element: HTMLElement): ReactRoot { - /* eslint-disable react/no-deprecated */ - return { - render(children: React.ReactChild | Iterable): void { - ReactDOM.render(children as any, element as any); - }, - unmount(): void { - ReactDOM.unmountComponentAtNode(element as any); - }, - }; - /* eslint-enable react/no-deprecated */ -} - -/** Uses React >= 18 createRoot if available or falls back to shim*/ -export function createRoot(element: HTMLElement): ReactRoot { - try { - // eslint-disable-next-line @typescript-eslint/no-var-requires - return require('react-dom/client').createRoot(element); - } catch { - return createRootShim(element); - } -} - -export const isLegacyReact = parseInt(React.version, 10) < 18; - export const act: typeof oldAct = (() => { try { // eslint-disable-next-line @typescript-eslint/no-var-requires @@ -50,30 +9,3 @@ export const act: typeof oldAct = (() => { return oldAct; } })(); - -// https://github.com/facebook/react/blob/12adaffef7105e2714f82651ea51936c563fe15c/packages/shared/enqueueTask.js#L13 -let enqueueTaskImpl: any = null; - -export function enqueueTask(task: (v: any) => void) { - if (enqueueTaskImpl === null) { - try { - // read require off the module object to get around the bundlers. - // we don't want them to detect a require and bundle a Node polyfill. - const requireString = `require${Math.random()}`.slice(0, 7); - const nodeRequire = module && module[requireString]; - // assuming we're in node, let's try to get node's - // version of setImmediate, bypassing fake timers if any. - enqueueTaskImpl = nodeRequire.call(module, 'timers').setImmediate; - } catch (_err) { - // we're in a browser - // we can't use regular timers because they may still be faked - // so we try MessageChannel+postMessage instead - enqueueTaskImpl = function (callback: () => void) { - const channel = new MessageChannel(); - channel.port1.onmessage = callback; - channel.port2.postMessage(undefined); - }; - } - } - return enqueueTaskImpl!(task); -} diff --git a/packages/react-testing/src/root.tsx b/packages/react-testing/src/root.tsx index 56c4ad6d9d..330e56897c 100644 --- a/packages/react-testing/src/root.tsx +++ b/packages/react-testing/src/root.tsx @@ -1,17 +1,12 @@ import React from 'react'; +import {createRoot} from 'react-dom/client'; import {flushSync} from 'react-dom'; import type {Root as ReactRoot} from 'react-dom/client'; import {findCurrentFiberUsingSlowPath} from 'react-reconciler/reflection.js'; import {TestWrapper} from './TestWrapper'; import {Element} from './element'; -import { - createRoot, - getInternals, - enqueueTask, - isLegacyReact, - act, -} from './compat'; +import {act} from './compat'; import type { Fiber, Node, @@ -316,11 +311,6 @@ export class Root implements Node { this.destroyed = true; await mountedPromise; this.actCallbacks.forEach((callback) => callback()); - - if (isLegacyReact) { - // flush macro task for react 17 only - await new Promise((resolve) => enqueueTask(resolve)); - } } setProps(props: Partial) { @@ -346,7 +336,7 @@ export class Root implements Node { if (this.wrapper == null) { this.root = null; } else if (this.mounted) { - const rootFiber = getInternals(this.wrapper.rootRef as any); + const rootFiber = (this.wrapper.rootRef as any)._reactInternals; const topElement = fiberToElement( findCurrentFiberUsingSlowPath(rootFiber), this, diff --git a/packages/react-testing/src/tests/compat.test.tsx b/packages/react-testing/src/tests/compat.test.tsx deleted file mode 100644 index b05a5e219d..0000000000 --- a/packages/react-testing/src/tests/compat.test.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import {getInternals} from '../compat'; -import type {ReactInstance} from '../types'; - -describe('compat', () => { - it('returns the fiber for react-16 style nodes', () => { - const fakeInstance: ReactInstance = {_reactInternalFiber: 'foo'} as any; - expect(getInternals(fakeInstance)).toBe('foo'); - }); - - it('returns the fiber for react-17 style nodes', () => { - const fakeInstance: ReactInstance = {_reactInternals: 'foo'} as any; - expect(getInternals(fakeInstance)).toBe('foo'); - }); -}); diff --git a/packages/react-testing/src/types.ts b/packages/react-testing/src/types.ts index 29c16ac671..6685d42c9b 100644 --- a/packages/react-testing/src/types.ts +++ b/packages/react-testing/src/types.ts @@ -189,13 +189,9 @@ export interface Fiber { memoizedState: unknown; } -export type ReactInstance = - | { - _reactInternals: Fiber; - } - | { - _reactInternalFiber: Fiber; - }; +export interface ReactInstance { + _reactInternalFiber: Fiber; +} export type Predicate = (node: Node) => boolean;