Skip to content
This repository has been archived by the owner on Oct 1, 2024. It is now read-only.

Remove React 17 compatability from react-testing #2820

Merged
merged 1 commit into from
Aug 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/empty-spiders-grow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@shopify/react-testing': major
Copy link
Member Author

@alex-page alex-page Aug 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I flagged this change as a major as it deletes backwards compatibility

---

Remove React 17 compatability
68 changes: 0 additions & 68 deletions packages/react-testing/src/compat.ts
Original file line number Diff line number Diff line change
@@ -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<React.ReactNode>): 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 {
Copy link
Member Author

@alex-page alex-page Aug 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// eslint-disable-next-line @typescript-eslint/no-var-requires
Expand All @@ -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);
}
16 changes: 3 additions & 13 deletions packages/react-testing/src/root.tsx
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -316,11 +311,6 @@ export class Root<Props> implements Node<Props> {
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<Props>) {
Expand All @@ -346,7 +336,7 @@ export class Root<Props> implements Node<Props> {
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,
Expand Down
14 changes: 0 additions & 14 deletions packages/react-testing/src/tests/compat.test.tsx

This file was deleted.

11 changes: 0 additions & 11 deletions packages/react-testing/src/tests/root.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,6 @@ describe('Root', () => {
await destroyAll();
});

it('works with react 16 style nodes', () => {
const root = new Root(<div />);

// in React 17 _reactInternalFiber is renamed to _reactInternals
const rootRef = (root as any).wrapper.rootRef;
rootRef._reactInternalFiber = rootRef._reactInternals;
delete rootRef._reactInternals;

expect(() => root.act(() => {})).not.toThrow();
});

it('delegates calls to the root element', () => {
const root = new Root(<div />);

Expand Down
10 changes: 3 additions & 7 deletions packages/react-testing/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,13 +189,9 @@ export interface Fiber {
memoizedState: unknown;
}

export type ReactInstance =
| {
_reactInternals: Fiber;
}
| {
_reactInternalFiber: Fiber;
};
export interface ReactInstance {
_reactInternals: Fiber;
}

export type Predicate = (node: Node<unknown>) => boolean;

Expand Down
Loading