Skip to content

Commit 1e4ccf9

Browse files
committed
Handle runtime config validation errors, add tests
1 parent 6627150 commit 1e4ccf9

3 files changed

Lines changed: 84 additions & 14 deletions

File tree

modules/@shopify/checkout-sheet-kit/src/index.ts

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -222,9 +222,9 @@ class ShopifyCheckoutSheet implements ShopifyCheckoutSheetKit {
222222
return false;
223223
}
224224

225-
this.validateAcceleratedCheckoutsConfiguration(config);
226-
227225
try {
226+
this.validateAcceleratedCheckoutsConfiguration(config);
227+
228228
const configured =
229229
await RNShopifyCheckoutSheetKit.configureAcceleratedCheckouts(
230230
config.storefrontDomain,
@@ -238,8 +238,8 @@ class ShopifyCheckoutSheet implements ShopifyCheckoutSheetKit {
238238
} catch (error) {
239239
// eslint-disable-next-line no-console
240240
console.error(
241-
'Failed to configured accelerated checkouts with config:',
242-
config,
241+
'[ShopifyCheckoutSheetKit] Failed to configure accelerated checkouts with',
242+
error,
243243
);
244244
return false;
245245
}
@@ -288,18 +288,34 @@ class ShopifyCheckoutSheet implements ShopifyCheckoutSheetKit {
288288
* Required Accelerated Checkouts configuration properties
289289
*/
290290
if (!acceleratedCheckouts?.storefrontDomain) {
291-
throw new Error('storefrontDomain is required');
291+
throw new Error('`storefrontDomain` is required');
292292
}
293293
if (!acceleratedCheckouts.storefrontAccessToken) {
294-
throw new Error('storefrontAccessToken is required');
294+
throw new Error('`storefrontAccessToken` is required');
295295
}
296296

297297
/**
298298
* Validate Apple Pay config if available
299299
*/
300300
if (acceleratedCheckouts.wallets?.applePay) {
301301
if (!acceleratedCheckouts.wallets.applePay.merchantIdentifier) {
302-
throw new Error('wallets.applePay.merchantIdentifier is required');
302+
throw new Error('`wallets.applePay.merchantIdentifier` is required');
303+
}
304+
305+
const expectedContactFields = Object.values(ApplePayContactField);
306+
const hasInvalidContactFields =
307+
Array.isArray(acceleratedCheckouts.wallets.applePay.contactFields) &&
308+
acceleratedCheckouts.wallets.applePay.contactFields.some(
309+
value =>
310+
!expectedContactFields.includes(
311+
value.toLowerCase() as ApplePayContactField,
312+
),
313+
);
314+
315+
if (hasInvalidContactFields) {
316+
throw new Error(
317+
`'wallets.applePay.contactFields' contains unexpected values. Expected "${expectedContactFields.join(', ')}", received "${acceleratedCheckouts.wallets.applePay.contactFields}"`,
318+
);
303319
}
304320
}
305321
}

modules/@shopify/checkout-sheet-kit/tests/index.test.ts

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/* eslint-disable no-new */
2+
/* eslint-disable no-console */
23

34
import {
45
LifecycleEventParseError,
@@ -772,10 +773,15 @@ describe('ShopifyCheckoutSheetKit', () => {
772773
...acceleratedConfig,
773774
storefrontDomain: '',
774775
};
776+
const expectedError = new Error('`storefrontDomain` is required');
775777

776778
await expect(
777779
instance.configureAcceleratedCheckouts(invalidConfig),
778-
).rejects.toThrow('storefrontDomain is required');
780+
).resolves.toBe(false);
781+
expect(console.error).toHaveBeenCalledWith(
782+
'[ShopifyCheckoutSheetKit] Failed to configure accelerated checkouts with',
783+
expectedError,
784+
);
779785
});
780786

781787
it('validates required storefrontAccessToken', async () => {
@@ -785,9 +791,15 @@ describe('ShopifyCheckoutSheetKit', () => {
785791
storefrontAccessToken: '',
786792
};
787793

794+
const expectedError = new Error('`storefrontAccessToken` is required');
795+
788796
await expect(
789797
instance.configureAcceleratedCheckouts(invalidConfig),
790-
).rejects.toThrow('storefrontAccessToken is required');
798+
).resolves.toBe(false);
799+
expect(console.error).toHaveBeenCalledWith(
800+
'[ShopifyCheckoutSheetKit] Failed to configure accelerated checkouts with',
801+
expectedError,
802+
);
791803
});
792804

793805
it('validates required merchantIdentifier when Apple Pay is configured', async () => {
@@ -802,9 +814,42 @@ describe('ShopifyCheckoutSheetKit', () => {
802814
},
803815
};
804816

817+
const expectedError = new Error(
818+
'`wallets.applePay.merchantIdentifier` is required',
819+
);
820+
805821
await expect(
806822
instance.configureAcceleratedCheckouts(invalidConfig),
807-
).rejects.toThrow('wallets.applePay.merchantIdentifier is required');
823+
).resolves.toBe(false);
824+
expect(console.error).toHaveBeenCalledWith(
825+
'[ShopifyCheckoutSheetKit] Failed to configure accelerated checkouts with',
826+
expectedError,
827+
);
828+
});
829+
830+
it('validates required contactFields when Apple Pay is configured', async () => {
831+
const instance = new ShopifyCheckoutSheet();
832+
const invalidConfig = {
833+
...acceleratedConfig,
834+
wallets: {
835+
applePay: {
836+
contactFields: ['invalid'],
837+
merchantIdentifier: 'merchant.test.com',
838+
},
839+
},
840+
};
841+
842+
const expectedError = new Error(
843+
`'wallets.applePay.contactFields' contains unexpected values. Expected "email, phone", received "invalid"`,
844+
);
845+
846+
await expect(
847+
instance.configureAcceleratedCheckouts(invalidConfig as any),
848+
).resolves.toBe(false);
849+
expect(console.error).toHaveBeenCalledWith(
850+
'[ShopifyCheckoutSheetKit] Failed to configure accelerated checkouts with',
851+
expectedError,
852+
);
808853
});
809854

810855
it('does not throw when Apple Pay wallet is not configured', async () => {

sample/src/App.tsx

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,17 @@ function AppWithNavigation({children}: PropsWithChildren) {
356356
};
357357
}, [appConfig.colorScheme, updatedColors]);
358358

359+
const [contactFields, setContactFields] = useState<ApplePayContactField[]>([
360+
ApplePayContactField.email,
361+
ApplePayContactField.phone,
362+
]);
363+
364+
useEffect(() => {
365+
setTimeout(() => {
366+
setContactFields(['invalid']);
367+
}, 3000);
368+
}, []);
369+
359370
const checkoutKitConfig: Configuration = useMemo(() => {
360371
return {
361372
...checkoutKitConfigDefaults,
@@ -380,15 +391,13 @@ function AppWithNavigation({children}: PropsWithChildren) {
380391
* In cases where customers are authenticated, email/phone will be provided through the customer property,
381392
* In cases where customers are NOT authenticated, we will collect email and phone number via the Apple Pay sheet.
382393
*/
383-
contactFields: appConfig.customerAuthenticated
384-
? []
385-
: [ApplePayContactField.email, ApplePayContactField.phone],
394+
contactFields: contactFields,
386395
merchantIdentifier: env.STOREFRONT_MERCHANT_IDENTIFIER!,
387396
},
388397
},
389398
},
390399
} as Configuration;
391-
}, [appConfig, checkoutKitThemeConfig]);
400+
}, [appConfig, checkoutKitThemeConfig, contactFields]);
392401

393402
return (
394403
<ShopifyCheckoutSheetProvider

0 commit comments

Comments
 (0)