Skip to content

Commit 165895e

Browse files
authored
Fixing the hook error handling to handle object components (#839)
* Fixing the hook error handling to handle object components * adding changeset * Keeping the hook error handling simple * Updating changeset
1 parent 38f520d commit 165895e

File tree

3 files changed

+18
-110
lines changed

3 files changed

+18
-110
lines changed

.changeset/twelve-trams-shine.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@paypal/react-paypal-js": patch
3+
---
4+
5+
Fixing the hook error handling to be simple and generic

packages/react-paypal-js/src/v6/utils.test.ts

Lines changed: 9 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,10 @@ describe("createPaymentSession", () => {
99
mockSetError = jest.fn();
1010
failedSdkRef = { current: null };
1111
mockSdkInstance = { id: "test-sdk-instance" };
12-
13-
// Clear any existing __paypal_sdk__ from previous tests
14-
delete (window as Window & { __paypal_sdk__?: unknown }).__paypal_sdk__;
1512
});
1613

1714
afterEach(() => {
1815
jest.clearAllMocks();
19-
// Cleanup __paypal_sdk__ after each test
20-
delete (window as Window & { __paypal_sdk__?: unknown }).__paypal_sdk__;
2116
});
2217

2318
describe("successful session creation", () => {
@@ -41,53 +36,10 @@ describe("createPaymentSession", () => {
4136
});
4237

4338
describe("error handling with component parameter", () => {
44-
test("should show specific component missing error when component is not loaded", () => {
45-
// Mock window with loaded components that don't include the required one
46-
(window as Window & { __paypal_sdk__?: unknown }).__paypal_sdk__ = {
47-
v6: {
48-
components: ["venmo-payments", "paypal-subscriptions"],
49-
},
50-
};
51-
52-
const sessionCreator = jest.fn().mockImplementation(() => {
53-
throw new Error("Component not loaded");
54-
});
55-
56-
const result = createPaymentSession(
57-
sessionCreator,
58-
failedSdkRef,
59-
mockSdkInstance,
60-
mockSetError,
61-
"paypal-payments",
62-
);
63-
64-
expect(result).toBeNull();
65-
66-
const thrownError = mockSetError.mock.calls[0][0];
67-
expect(thrownError.message).toContain(
68-
"Failed to create payment session",
69-
);
70-
expect(thrownError.message).toContain(
71-
'The required component "paypal-payments" is not loaded',
72-
);
73-
expect(thrownError.message).toContain(
74-
"Currently loaded components: [venmo-payments, paypal-subscriptions]",
75-
);
76-
expect(thrownError.message).toContain(
77-
'Please add "paypal-payments" to your SDK components array',
78-
);
79-
});
80-
81-
test("should show component appears loaded error when component is in loaded list", () => {
82-
// Mock window with loaded components including the required one
83-
(window as Window & { __paypal_sdk__?: unknown }).__paypal_sdk__ = {
84-
v6: {
85-
components: ["paypal-payments", "venmo-payments"],
86-
},
87-
};
88-
39+
test("should handle session creation failure with proper error message and error preservation", () => {
40+
const originalError = new Error("Component missing");
8941
const sessionCreator = jest.fn().mockImplementation(() => {
90-
throw new Error("Other error");
42+
throw originalError;
9143
});
9244

9345
const result = createPaymentSession(
@@ -99,36 +51,15 @@ describe("createPaymentSession", () => {
9951
);
10052

10153
expect(result).toBeNull();
54+
expect(mockSetError).toHaveBeenCalledTimes(1);
10255

10356
const thrownError = mockSetError.mock.calls[0][0];
104-
expect(thrownError.message).toContain(
105-
'The component "paypal-payments" appears to be loaded but the session failed to create',
106-
);
107-
});
108-
109-
test("should show generic component error when component is provided but no loaded components info", () => {
110-
// Ensure no __paypal_sdk__
111-
delete (window as Window & { __paypal_sdk__?: unknown })
112-
.__paypal_sdk__;
113-
114-
const sessionCreator = jest.fn().mockImplementation(() => {
115-
throw new Error("Component missing");
116-
});
117-
118-
const result = createPaymentSession(
119-
sessionCreator,
120-
failedSdkRef,
121-
mockSdkInstance,
122-
mockSetError,
123-
"paypal-payments",
124-
);
125-
126-
expect(result).toBeNull();
127-
128-
const thrownError = mockSetError.mock.calls[0][0];
129-
expect(thrownError.message).toContain(
130-
'This may occur if the required component "paypal-payments" is not included in the SDK components array',
57+
expect(thrownError).toBeInstanceOf(Error);
58+
expect(thrownError.message).toBe(
59+
'Failed to create payment session. This may occur if the required component "paypal-payments" is not included in the SDK components array.',
13160
);
61+
expect(thrownError.cause).toBe(originalError);
62+
expect(failedSdkRef.current).toBe(mockSdkInstance);
13263
});
13364
});
13465

packages/react-paypal-js/src/v6/utils.ts

Lines changed: 4 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -261,40 +261,12 @@ export function createPaymentSession<T>(
261261
} catch (err) {
262262
failedSdkRef.current = sdkInstance;
263263

264-
const loadedComponents = (
265-
window as Window & {
266-
__paypal_sdk__?: { v6: { components?: string[] } };
267-
}
268-
).__paypal_sdk__?.v6?.components;
269-
270-
const errorMessage = buildErrorMessage(component, loadedComponents);
271-
const detailedError = new Error(errorMessage, { cause: err });
264+
const detailedError = new Error(
265+
`Failed to create payment session. This may occur if the required component "${component}" is not included in the SDK components array.`,
266+
{ cause: err },
267+
);
272268

273269
setError(detailedError);
274270
return null;
275271
}
276272
}
277-
278-
function buildErrorMessage(
279-
component: string,
280-
loadedComponents: string[] | undefined,
281-
): string {
282-
const baseMessage = "Failed to create payment session.";
283-
const hasLoadedComponents = Array.isArray(loadedComponents);
284-
const componentsList = hasLoadedComponents
285-
? loadedComponents.join(", ")
286-
: "";
287-
288-
// Component provided but no loaded components info
289-
if (!hasLoadedComponents) {
290-
return `${baseMessage} This may occur if the required component "${component}" is not included in the SDK components array.`;
291-
}
292-
293-
// Component is missing from loaded components
294-
if (!loadedComponents.includes(component)) {
295-
return `${baseMessage} The required component "${component}" is not loaded. Currently loaded components: [${componentsList}]. Please add "${component}" to your SDK components array.`;
296-
}
297-
298-
// Component appears to be loaded but session creation still failed
299-
return `${baseMessage} The component "${component}" appears to be loaded but the session failed to create.`;
300-
}

0 commit comments

Comments
 (0)