diff --git a/src/components/PayPalButtons.test.js b/src/components/PayPalButtons.test.js
index c61043c7..293cf127 100644
--- a/src/components/PayPalButtons.test.js
+++ b/src/components/PayPalButtons.test.js
@@ -1,5 +1,11 @@
import React, { useState } from "react";
-import { render, waitFor, screen, fireEvent } from "@testing-library/react";
+import {
+ render,
+ waitFor,
+ screen,
+ fireEvent,
+ act,
+} from "@testing-library/react";
import { PayPalScriptProvider } from "../ScriptContext";
import PayPalButtons from "./PayPalButtons";
@@ -11,13 +17,11 @@ jest.mock("@paypal/paypal-js", () => ({
}));
describe("", () => {
- let consoleErrorSpy;
beforeEach(() => {
window.paypal = {};
loadScript.mockResolvedValue(window.paypal);
-
- consoleErrorSpy = jest.spyOn(console, "error");
- console.error.mockImplementation(() => {});
+ const consoleErrorSpy = jest.spyOn(console, "error");
+ consoleErrorSpy.mockImplementation(() => {});
});
afterEach(() => {
jest.clearAllMocks();
@@ -98,14 +102,14 @@ describe("", () => {
expect(window.paypal.Buttons).toHaveBeenCalled();
});
- const onInitCallback = window.paypal.Buttons.mock.calls[0][0].onInit;
-
const onInitActions = {
enable: jest.fn(),
disable: jest.fn(),
};
- onInitCallback({}, onInitActions);
+ act(() =>
+ window.paypal.Buttons.mock.calls[0][0].onInit({}, onInitActions)
+ );
await waitFor(() => {
expect(onInitCallbackMock).toHaveBeenCalled();
@@ -183,8 +187,10 @@ describe("", () => {
expect(screen.getByTestId("orderID").innerHTML).toBe("1");
- // call createOrder() to trigger a state change
- window.paypal.Buttons.mock.calls[0][0].createOrder();
+ act(() =>
+ // call createOrder() to trigger a state change
+ window.paypal.Buttons.mock.calls[0][0].createOrder()
+ );
await waitFor(() =>
expect(screen.getByTestId("orderID").innerHTML).toBe("2")
@@ -246,17 +252,21 @@ describe("", () => {
};
};
+ const onError = jest.fn();
+
+ const wrapper = ({ children }) => (
+ {children}
+ );
+
render(
-
+ ,
+ { wrapper }
);
- await waitFor(() =>
- expect(consoleErrorSpy).toHaveBeenCalledWith(
- expect.stringMatching(/Window closed/)
- )
- );
+ await waitFor(() => expect(onError).toHaveBeenCalled());
+ expect(onError.mock.calls[0][0].message).toMatchSnapshot();
});
});
diff --git a/src/components/PayPalButtons.tsx b/src/components/PayPalButtons.tsx
index b9af937f..bcd27e34 100644
--- a/src/components/PayPalButtons.tsx
+++ b/src/components/PayPalButtons.tsx
@@ -88,9 +88,15 @@ export default function PayPalButtons({
}
buttons.current.render(buttonsContainerRef.current).catch((err) => {
- console.error(
- `Failed to render component. ${err}`
- );
+ // component failed to render, possibly because it was closed or destroyed.
+ if (buttonsContainerRef.current === null) {
+ // ref is no longer in the DOM, we can safely ignore the error
+ return;
+ }
+ // ref is still in the DOM
+ setErrorState(() => {
+ throw new Error(`Failed to render component. ${err}`);
+ });
});
return closeButtonsComponent;
diff --git a/src/components/__snapshots__/PayPalButtons.test.js.snap b/src/components/__snapshots__/PayPalButtons.test.js.snap
index 5f90ae4b..f49b6076 100644
--- a/src/components/__snapshots__/PayPalButtons.test.js.snap
+++ b/src/components/__snapshots__/PayPalButtons.test.js.snap
@@ -1,5 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
+exports[` should catch and log zoid render errors 1`] = `"Failed to render component. Window closed"`;
+
exports[` should throw an error when no components are passed to the PayPalScriptProvider 1`] = `"Unable to render because window.paypal.Buttons is undefined."`;
exports[` should throw an error when the 'buttons' component is missing from the components list passed to the PayPalScriptProvider 1`] = `