Skip to content

Commit

Permalink
React 17 compatibility (as patch to 1.28) (#2431)
Browse files Browse the repository at this point in the history
* fix: fixes import in renderReactInWebComponent

* test: fixes unit tests for renderReactInWebComponent

---------

Co-authored-by: Kevin Ghadyani <kevin.ghadyani@okta.com>
  • Loading branch information
benschell-okta and KevinGhadyani-Okta authored Dec 2, 2024
1 parent fe438db commit 8a51b78
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 20 deletions.
36 changes: 21 additions & 15 deletions packages/odyssey-react-mui/src/labs/UiShell/renderUiShell.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
* See the License for the specific language governing permissions and limitations under the License.
*/

import { act } from "@testing-library/react";
import { act, waitFor } from "@testing-library/react";

import { renderUiShell } from "./renderUiShell";
import {
Expand Down Expand Up @@ -126,9 +126,11 @@ describe("renderUiShell", () => {
});
});

expect(
rootElement.querySelector(reactWebComponentElementName)!.shadowRoot,
).toHaveTextContent(appName);
await waitFor(() => {
expect(
rootElement.querySelector(reactWebComponentElementName)!.shadowRoot,
).toHaveTextContent(appName);
});
});

test("renders `UiShell` with immediately updated props", async () => {
Expand All @@ -153,9 +155,11 @@ describe("renderUiShell", () => {
});
});

expect(
rootElement.querySelector(reactWebComponentElementName)!.shadowRoot,
).toHaveTextContent(appName);
await waitFor(() => {
expect(
rootElement.querySelector(reactWebComponentElementName)!.shadowRoot,
).toHaveTextContent(appName);
});
});

test("renders `<slot>` in the event of an error", async () => {
Expand Down Expand Up @@ -184,14 +188,16 @@ describe("renderUiShell", () => {
);
});

consoleErrorSpy.mockRestore();
await waitFor(() => {
expect(onError).toHaveBeenCalledTimes(1);
expect(consoleError).toHaveBeenCalledTimes(1);
expect(
rootElement
.querySelector(reactWebComponentElementName)!
.shadowRoot?.querySelector("slot"),
).toBeInstanceOf(HTMLSlotElement);
});

expect(onError).toHaveBeenCalledTimes(1);
expect(consoleError).toHaveBeenCalledTimes(1);
expect(
rootElement
.querySelector(reactWebComponentElementName)!
.shadowRoot?.querySelector("slot"),
).toBeInstanceOf(HTMLSlotElement);
consoleErrorSpy.mockRestore();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
*/

import { type ReactNode } from "react";
import { createRoot, type Root } from "react-dom/client";
import type { Root } from "react-dom/client";

/**
* Creates elements for a Shadow DOM that Odyssey will render into.
Expand Down Expand Up @@ -56,8 +56,8 @@ export type GetReactComponentInWebComponent = (

export class ReactInWebComponentElement extends HTMLElement {
getReactComponent: GetReactComponentInWebComponent;
reactRoot: Root;
reactRootElements: ReactRootElements;
reactRootPromise: Promise<Root>;

constructor(getReactComponent: GetReactComponentInWebComponent) {
super();
Expand All @@ -81,15 +81,20 @@ export class ReactInWebComponentElement extends HTMLElement {
shadowRoot.appendChild(this.reactRootElements.stylesRootElement);
shadowRoot.appendChild(this.reactRootElements.appRootElement);

this.reactRoot = createRoot(this.reactRootElements.appRootElement);
// If we want to support React v17 in the future, we can use a try-catch on the import to grab the old `ReactDOM.render` function if `react-dom/client` errors. --Kevin Ghadyani
this.reactRootPromise = import("react-dom/client").then(({ createRoot }) =>
createRoot(this.reactRootElements.appRootElement),
);
}

connectedCallback() {
this.reactRoot.render(this.getReactComponent(this.reactRootElements));
this.reactRootPromise.then((reactRoot) =>
reactRoot.render(this.getReactComponent(this.reactRootElements)),
);
}

disconnectedCallback() {
this.reactRoot.unmount();
this.reactRootPromise.then((reactRoot) => reactRoot.unmount());
}
}

Expand Down

0 comments on commit 8a51b78

Please sign in to comment.