@funnelsgrove/payments 0.1.33 → 0.1.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/providers/stripe/WalletSubscriptionCheckoutSlot.d.ts +2 -1
- package/dist/providers/stripe/WalletSubscriptionCheckoutSlot.js +22 -14
- package/dist/providers/stripe/useStripeSubscriptionCheckoutSession.js +25 -6
- package/dist/services/runtime-mode.service.d.ts +6 -0
- package/dist/services/runtime-mode.service.js +12 -0
- package/dist/testing/walletCheckoutSmoke.d.ts +92 -0
- package/dist/testing/walletCheckoutSmoke.js +111 -0
- package/package.json +3 -2
package/dist/index.d.ts
CHANGED
|
@@ -21,3 +21,4 @@ export * from './components/shared/StripeExpressCheckoutButton.js';
|
|
|
21
21
|
export * from './components/shared/StripeExpressCheckoutElement.js';
|
|
22
22
|
export * from './components/shared/StripePlanSelector.js';
|
|
23
23
|
export * from './components/shared/walletPlatform.js';
|
|
24
|
+
export * from './testing/walletCheckoutSmoke.js';
|
package/dist/index.js
CHANGED
|
@@ -21,3 +21,4 @@ export * from './components/shared/StripeExpressCheckoutButton.js';
|
|
|
21
21
|
export * from './components/shared/StripeExpressCheckoutElement.js';
|
|
22
22
|
export * from './components/shared/StripePlanSelector.js';
|
|
23
23
|
export * from './components/shared/walletPlatform.js';
|
|
24
|
+
export * from './testing/walletCheckoutSmoke.js';
|
|
@@ -7,13 +7,14 @@ export type WalletSubscriptionCheckoutRenderStateInput = {
|
|
|
7
7
|
hasStripePromise: boolean;
|
|
8
8
|
suspended: boolean;
|
|
9
9
|
walletAvailable: boolean | null;
|
|
10
|
+
walletPreparing: boolean;
|
|
10
11
|
};
|
|
11
12
|
export type WalletSubscriptionCheckoutRenderState = {
|
|
12
13
|
placeholderIsPreparing: boolean;
|
|
13
14
|
shouldRenderExpressCheckout: boolean;
|
|
14
15
|
shouldRenderPlaceholder: boolean;
|
|
15
16
|
};
|
|
16
|
-
export declare function getWalletSubscriptionCheckoutRenderState({ expressCheckoutAllowed, hasActiveClientSecret, hasStripePromise, suspended, walletAvailable, }: WalletSubscriptionCheckoutRenderStateInput): WalletSubscriptionCheckoutRenderState;
|
|
17
|
+
export declare function getWalletSubscriptionCheckoutRenderState({ expressCheckoutAllowed, hasActiveClientSecret, hasStripePromise, suspended, walletAvailable, walletPreparing, }: WalletSubscriptionCheckoutRenderStateInput): WalletSubscriptionCheckoutRenderState;
|
|
17
18
|
type WalletPlaceholderButtonProps = {
|
|
18
19
|
className?: string;
|
|
19
20
|
disabled: boolean;
|
|
@@ -3,7 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
3
3
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
4
4
|
import { StripeExpressCheckoutElement } from '../../components/shared/StripeExpressCheckoutElement.js';
|
|
5
5
|
import { isInactiveCheckoutSessionError, } from './useStripeSubscriptionCheckoutSession.js';
|
|
6
|
-
export function getWalletSubscriptionCheckoutRenderState({ expressCheckoutAllowed, hasActiveClientSecret, hasStripePromise, suspended, walletAvailable, }) {
|
|
6
|
+
export function getWalletSubscriptionCheckoutRenderState({ expressCheckoutAllowed, hasActiveClientSecret, hasStripePromise, suspended, walletAvailable, walletPreparing, }) {
|
|
7
7
|
const shouldRenderExpressCheckout = !suspended &&
|
|
8
8
|
expressCheckoutAllowed &&
|
|
9
9
|
walletAvailable !== false &&
|
|
@@ -14,7 +14,7 @@ export function getWalletSubscriptionCheckoutRenderState({ expressCheckoutAllowe
|
|
|
14
14
|
expressCheckoutAllowed &&
|
|
15
15
|
walletAvailable === null;
|
|
16
16
|
return {
|
|
17
|
-
placeholderIsPreparing: shouldRenderPlaceholder,
|
|
17
|
+
placeholderIsPreparing: shouldRenderPlaceholder && walletPreparing,
|
|
18
18
|
shouldRenderExpressCheckout,
|
|
19
19
|
shouldRenderPlaceholder,
|
|
20
20
|
};
|
|
@@ -43,19 +43,28 @@ export function WalletSubscriptionCheckoutSlot({ amountCents, availabilityPaymen
|
|
|
43
43
|
hasStripePromise: Boolean(session.stripePromise),
|
|
44
44
|
suspended,
|
|
45
45
|
walletAvailable,
|
|
46
|
+
walletPreparing: session.loading.wallet,
|
|
46
47
|
});
|
|
47
48
|
const serverUpdateKey = session.activeClientSecret &&
|
|
48
49
|
session.checkoutSessionId &&
|
|
49
50
|
session.activePlanKey !== session.planKey
|
|
50
51
|
? session.planKey
|
|
51
52
|
: null;
|
|
52
|
-
const
|
|
53
|
+
const reportWalletAvailability = useCallback((intentKey, available) => {
|
|
53
54
|
setWalletAvailability({
|
|
54
|
-
available:
|
|
55
|
+
available: available,
|
|
55
56
|
intentKey,
|
|
56
57
|
});
|
|
57
|
-
onAvailabilityChange === null || onAvailabilityChange === void 0 ? void 0 : onAvailabilityChange(
|
|
58
|
+
onAvailabilityChange === null || onAvailabilityChange === void 0 ? void 0 : onAvailabilityChange(available);
|
|
58
59
|
}, [onAvailabilityChange]);
|
|
60
|
+
const reportWalletPreparationFailure = useCallback((intentKey) => {
|
|
61
|
+
setWalletAvailability((current) => current.intentKey === intentKey
|
|
62
|
+
? current
|
|
63
|
+
: {
|
|
64
|
+
available: null,
|
|
65
|
+
intentKey,
|
|
66
|
+
});
|
|
67
|
+
}, []);
|
|
59
68
|
useEffect(() => {
|
|
60
69
|
if (slotDisabled ||
|
|
61
70
|
suspended ||
|
|
@@ -72,12 +81,12 @@ export function WalletSubscriptionCheckoutSlot({ amountCents, availabilityPaymen
|
|
|
72
81
|
void (async () => {
|
|
73
82
|
const readyClientSecret = await session.prepareWalletCheckout();
|
|
74
83
|
if (!readyClientSecret) {
|
|
75
|
-
|
|
84
|
+
reportWalletPreparationFailure(requestKey);
|
|
76
85
|
}
|
|
77
86
|
})();
|
|
78
87
|
}, [
|
|
79
88
|
expressCheckoutAllowed,
|
|
80
|
-
|
|
89
|
+
reportWalletPreparationFailure,
|
|
81
90
|
session,
|
|
82
91
|
slotDisabled,
|
|
83
92
|
suspended,
|
|
@@ -96,11 +105,7 @@ export function WalletSubscriptionCheckoutSlot({ amountCents, availabilityPaymen
|
|
|
96
105
|
onError === null || onError === void 0 ? void 0 : onError(message);
|
|
97
106
|
};
|
|
98
107
|
const handleAvailabilityChange = (available) => {
|
|
99
|
-
|
|
100
|
-
available,
|
|
101
|
-
intentKey: session.intentKey,
|
|
102
|
-
});
|
|
103
|
-
onAvailabilityChange === null || onAvailabilityChange === void 0 ? void 0 : onAvailabilityChange(available);
|
|
108
|
+
reportWalletAvailability(session.intentKey, available);
|
|
104
109
|
};
|
|
105
110
|
const handlePlaceholderClick = async () => {
|
|
106
111
|
if (slotDisabled || session.loading.wallet) {
|
|
@@ -112,9 +117,12 @@ export function WalletSubscriptionCheckoutSlot({ amountCents, availabilityPaymen
|
|
|
112
117
|
}
|
|
113
118
|
const readyClientSecret = await session.prepareWalletCheckout();
|
|
114
119
|
if (!readyClientSecret) {
|
|
115
|
-
|
|
120
|
+
reportWalletPreparationFailure(session.intentKey);
|
|
116
121
|
}
|
|
117
122
|
};
|
|
123
|
+
const placeholderRenderer = placeholderIsPreparing
|
|
124
|
+
? renderPreparingPlaceholder !== null && renderPreparingPlaceholder !== void 0 ? renderPreparingPlaceholder : renderPlaceholder
|
|
125
|
+
: renderPlaceholder;
|
|
118
126
|
return (_jsxs(_Fragment, { children: [shouldRenderPlaceholder || shouldRenderExpressCheckout ? (_jsxs("div", { className: [
|
|
119
127
|
'wallet-subscription-checkout-slot',
|
|
120
128
|
placeholderIsPreparing ? 'is-loading' : '',
|
|
@@ -123,7 +131,7 @@ export function WalletSubscriptionCheckoutSlot({ amountCents, availabilityPaymen
|
|
|
123
131
|
.filter(Boolean)
|
|
124
132
|
.join(' '), "aria-busy": placeholderIsPreparing || undefined, children: [shouldRenderExpressCheckout &&
|
|
125
133
|
session.activeClientSecret &&
|
|
126
|
-
session.stripePromise ? (_jsx(StripeExpressCheckoutElement, { amountCents: amountCents, availabilityPaymentMethods: [availabilityPaymentMethod], beforeConfirm: beforeConfirm, className: className, clientSecret: session.activeClientSecret, customerEmail: customerEmail, customerName: customerName, onAvailabilityChange: handleAvailabilityChange, onError: handleError, onSuccess: onSuccess, options: options, returnUrl: returnUrl, serverUpdateKey: serverUpdateKey, stripePromise: session.stripePromise, summaryLabel: summaryLabel, onServerUpdate: session.updateCheckoutSessionPlan })) : null, shouldRenderPlaceholder ? (_jsx("div", { className: 'wallet-subscription-checkout-slot__placeholder', children: (
|
|
134
|
+
session.stripePromise ? (_jsx(StripeExpressCheckoutElement, { amountCents: amountCents, availabilityPaymentMethods: [availabilityPaymentMethod], beforeConfirm: beforeConfirm, className: className, clientSecret: session.activeClientSecret, customerEmail: customerEmail, customerName: customerName, onAvailabilityChange: handleAvailabilityChange, onError: handleError, onSuccess: onSuccess, options: options, returnUrl: returnUrl, serverUpdateKey: serverUpdateKey, stripePromise: session.stripePromise, summaryLabel: summaryLabel, onServerUpdate: session.updateCheckoutSessionPlan })) : null, shouldRenderPlaceholder ? (_jsx("div", { className: 'wallet-subscription-checkout-slot__placeholder', children: placeholderRenderer({
|
|
127
135
|
className,
|
|
128
136
|
disabled: slotDisabled,
|
|
129
137
|
label: placeholderLabel,
|
|
@@ -70,6 +70,10 @@ export function useStripeSubscriptionCheckoutSession({ checkoutMode, analyticsMe
|
|
|
70
70
|
const activePlanKey = clientSecretIntentKey === intentKey ? clientSecretPlanKey : null;
|
|
71
71
|
const stripePromise = useMemo(() => getStripePromise(checkoutMode, runtimeStripePublishableKey), [checkoutMode, runtimeStripePublishableKey]);
|
|
72
72
|
const previousIntentKeyRef = useRef(intentKey);
|
|
73
|
+
const analyticsMetadataRef = useRef(analyticsMetadata);
|
|
74
|
+
useEffect(() => {
|
|
75
|
+
analyticsMetadataRef.current = analyticsMetadata;
|
|
76
|
+
}, [analyticsMetadata]);
|
|
73
77
|
const clearActiveCheckoutSession = useCallback(() => {
|
|
74
78
|
requestIdRef.current += 1;
|
|
75
79
|
creatingIntentRef.current = null;
|
|
@@ -129,7 +133,7 @@ export function useStripeSubscriptionCheckoutSession({ checkoutMode, analyticsMe
|
|
|
129
133
|
try {
|
|
130
134
|
const response = await createStripeSubscriptionCheckout({
|
|
131
135
|
plan,
|
|
132
|
-
analyticsMetadata,
|
|
136
|
+
analyticsMetadata: analyticsMetadataRef.current,
|
|
133
137
|
couponId,
|
|
134
138
|
customerEmail,
|
|
135
139
|
returnUrl,
|
|
@@ -173,7 +177,6 @@ export function useStripeSubscriptionCheckoutSession({ checkoutMode, analyticsMe
|
|
|
173
177
|
return subscriptionRequest;
|
|
174
178
|
}, [
|
|
175
179
|
activeClientSecret,
|
|
176
|
-
analyticsMetadata,
|
|
177
180
|
checkoutMode,
|
|
178
181
|
clearActiveCheckoutSession,
|
|
179
182
|
configured,
|
|
@@ -228,7 +231,7 @@ export function useStripeSubscriptionCheckoutSession({ checkoutMode, analyticsMe
|
|
|
228
231
|
await updateStripeSubscriptionCheckoutPlan({
|
|
229
232
|
checkoutSessionId: activeCheckoutSessionId,
|
|
230
233
|
plan,
|
|
231
|
-
analyticsMetadata,
|
|
234
|
+
analyticsMetadata: analyticsMetadataRef.current,
|
|
232
235
|
couponId,
|
|
233
236
|
customerEmail,
|
|
234
237
|
user_id: userId,
|
|
@@ -245,7 +248,6 @@ export function useStripeSubscriptionCheckoutSession({ checkoutMode, analyticsMe
|
|
|
245
248
|
}, [
|
|
246
249
|
activeCheckoutSessionId,
|
|
247
250
|
activePlanKey,
|
|
248
|
-
analyticsMetadata,
|
|
249
251
|
checkoutMode,
|
|
250
252
|
configured,
|
|
251
253
|
couponId,
|
|
@@ -257,7 +259,7 @@ export function useStripeSubscriptionCheckoutSession({ checkoutMode, analyticsMe
|
|
|
257
259
|
setError,
|
|
258
260
|
userId,
|
|
259
261
|
]);
|
|
260
|
-
return {
|
|
262
|
+
return useMemo(() => ({
|
|
261
263
|
activeClientSecret,
|
|
262
264
|
activePlanKey,
|
|
263
265
|
checkoutSessionId: activeCheckoutSessionId,
|
|
@@ -275,5 +277,22 @@ export function useStripeSubscriptionCheckoutSession({ checkoutMode, analyticsMe
|
|
|
275
277
|
setError,
|
|
276
278
|
stripePromise,
|
|
277
279
|
updateCheckoutSessionPlan,
|
|
278
|
-
}
|
|
280
|
+
}), [
|
|
281
|
+
activeCheckoutSessionId,
|
|
282
|
+
activeClientSecret,
|
|
283
|
+
activePlanKey,
|
|
284
|
+
configured,
|
|
285
|
+
error,
|
|
286
|
+
intentKey,
|
|
287
|
+
loading,
|
|
288
|
+
planKey,
|
|
289
|
+
prepareCardCheckout,
|
|
290
|
+
prepareWalletCheckout,
|
|
291
|
+
reset,
|
|
292
|
+
restartCardCheckout,
|
|
293
|
+
restartWalletCheckout,
|
|
294
|
+
setError,
|
|
295
|
+
stripePromise,
|
|
296
|
+
updateCheckoutSessionPlan,
|
|
297
|
+
]);
|
|
279
298
|
}
|
|
@@ -1 +1,7 @@
|
|
|
1
|
+
import { type RuntimeMode } from '@funnelsgrove/runtime';
|
|
1
2
|
export * from '@funnelsgrove/runtime';
|
|
3
|
+
export type PaymentRuntimeConfig = {
|
|
4
|
+
funnelSdkPublishableKey?: string | null;
|
|
5
|
+
};
|
|
6
|
+
export declare const resolvePaymentRuntimeMode: (runtimeMode: RuntimeMode, runtimeConfig?: PaymentRuntimeConfig | null) => RuntimeMode;
|
|
7
|
+
export declare const usePaymentRuntimeMode: (runtimeConfig?: PaymentRuntimeConfig | null) => RuntimeMode;
|
|
@@ -1 +1,13 @@
|
|
|
1
|
+
import { useMemo } from 'react';
|
|
2
|
+
import { useRuntimeMode } from '@funnelsgrove/runtime';
|
|
1
3
|
export * from '@funnelsgrove/runtime';
|
|
4
|
+
export const resolvePaymentRuntimeMode = (runtimeMode, runtimeConfig) => {
|
|
5
|
+
void runtimeConfig;
|
|
6
|
+
return runtimeMode;
|
|
7
|
+
};
|
|
8
|
+
export const usePaymentRuntimeMode = (runtimeConfig) => {
|
|
9
|
+
var _a;
|
|
10
|
+
const [runtimeMode] = useRuntimeMode();
|
|
11
|
+
const funnelSdkPublishableKey = (_a = runtimeConfig === null || runtimeConfig === void 0 ? void 0 : runtimeConfig.funnelSdkPublishableKey) !== null && _a !== void 0 ? _a : null;
|
|
12
|
+
return useMemo(() => resolvePaymentRuntimeMode(runtimeMode, { funnelSdkPublishableKey }), [funnelSdkPublishableKey, runtimeMode]);
|
|
13
|
+
};
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
export type WalletCheckoutSmokeProfileId = 'mobile-safari' | 'mobile-chrome';
|
|
2
|
+
export type WalletCheckoutSmokeProfile = {
|
|
3
|
+
id: WalletCheckoutSmokeProfileId;
|
|
4
|
+
name: string;
|
|
5
|
+
userAgent: string;
|
|
6
|
+
viewport: {
|
|
7
|
+
width: number;
|
|
8
|
+
height: number;
|
|
9
|
+
isMobile: boolean;
|
|
10
|
+
hasTouch: boolean;
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
export type WalletCheckoutSmokeSnapshot = {
|
|
14
|
+
blockingOverlayVisible: boolean;
|
|
15
|
+
cardFallbackVisible: boolean;
|
|
16
|
+
subscriptionRequestSucceeded: boolean;
|
|
17
|
+
walletSlotState: 'ready' | 'unavailable' | 'unknown';
|
|
18
|
+
};
|
|
19
|
+
export type WalletCheckoutSmokeEvaluation = {
|
|
20
|
+
failures: string[];
|
|
21
|
+
ok: boolean;
|
|
22
|
+
};
|
|
23
|
+
export type WalletCheckoutSmokeSelectors = {
|
|
24
|
+
blockingOverlay?: string;
|
|
25
|
+
cardFallback: string;
|
|
26
|
+
walletSlot: string;
|
|
27
|
+
};
|
|
28
|
+
export type WalletCheckoutSmokeOptions = {
|
|
29
|
+
profiles?: WalletCheckoutSmokeProfile[];
|
|
30
|
+
selectors: WalletCheckoutSmokeSelectors;
|
|
31
|
+
subscriptionRequestPath?: string;
|
|
32
|
+
timeoutMs?: number;
|
|
33
|
+
url: string;
|
|
34
|
+
};
|
|
35
|
+
export type WalletCheckoutSmokeProfileResult = WalletCheckoutSmokeEvaluation & {
|
|
36
|
+
profileId: WalletCheckoutSmokeProfileId;
|
|
37
|
+
snapshot: WalletCheckoutSmokeSnapshot;
|
|
38
|
+
};
|
|
39
|
+
export type WalletCheckoutSmokeResult = {
|
|
40
|
+
ok: boolean;
|
|
41
|
+
results: WalletCheckoutSmokeProfileResult[];
|
|
42
|
+
};
|
|
43
|
+
type PlaywrightPage = {
|
|
44
|
+
click: (selector: string, options?: {
|
|
45
|
+
timeout?: number;
|
|
46
|
+
}) => Promise<void>;
|
|
47
|
+
close?: () => Promise<void>;
|
|
48
|
+
goto: (url: string, options?: {
|
|
49
|
+
waitUntil?: 'domcontentloaded' | 'load' | 'networkidle';
|
|
50
|
+
}) => Promise<unknown>;
|
|
51
|
+
isVisible: (selector: string, options?: {
|
|
52
|
+
timeout?: number;
|
|
53
|
+
}) => Promise<boolean>;
|
|
54
|
+
waitForLoadState: (state?: 'domcontentloaded' | 'load' | 'networkidle', options?: {
|
|
55
|
+
timeout?: number;
|
|
56
|
+
}) => Promise<void>;
|
|
57
|
+
waitForResponse: (predicate: (response: {
|
|
58
|
+
status: () => number;
|
|
59
|
+
url: () => string;
|
|
60
|
+
}) => boolean, options?: {
|
|
61
|
+
timeout?: number;
|
|
62
|
+
}) => Promise<unknown>;
|
|
63
|
+
waitForSelector: (selector: string, options?: {
|
|
64
|
+
state?: 'attached' | 'detached' | 'hidden' | 'visible';
|
|
65
|
+
timeout?: number;
|
|
66
|
+
}) => Promise<unknown>;
|
|
67
|
+
};
|
|
68
|
+
type PlaywrightContext = {
|
|
69
|
+
close: () => Promise<void>;
|
|
70
|
+
newPage: () => Promise<PlaywrightPage>;
|
|
71
|
+
};
|
|
72
|
+
type PlaywrightBrowser = {
|
|
73
|
+
close: () => Promise<void>;
|
|
74
|
+
newContext: (options: {
|
|
75
|
+
hasTouch: boolean;
|
|
76
|
+
isMobile: boolean;
|
|
77
|
+
userAgent: string;
|
|
78
|
+
viewport: {
|
|
79
|
+
width: number;
|
|
80
|
+
height: number;
|
|
81
|
+
};
|
|
82
|
+
}) => Promise<PlaywrightContext>;
|
|
83
|
+
};
|
|
84
|
+
type PlaywrightChromium = {
|
|
85
|
+
launch: (options?: {
|
|
86
|
+
headless?: boolean;
|
|
87
|
+
}) => Promise<PlaywrightBrowser>;
|
|
88
|
+
};
|
|
89
|
+
export declare function buildWalletCheckoutSmokeProfiles(): WalletCheckoutSmokeProfile[];
|
|
90
|
+
export declare function evaluateWalletCheckoutSmokeSnapshot(snapshot: WalletCheckoutSmokeSnapshot): WalletCheckoutSmokeEvaluation;
|
|
91
|
+
export declare function runWalletCheckoutSmokeTest(chromium: PlaywrightChromium, options: WalletCheckoutSmokeOptions): Promise<WalletCheckoutSmokeResult>;
|
|
92
|
+
export {};
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
export function buildWalletCheckoutSmokeProfiles() {
|
|
2
|
+
return [
|
|
3
|
+
{
|
|
4
|
+
id: 'mobile-safari',
|
|
5
|
+
name: 'Mobile Safari',
|
|
6
|
+
userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Mobile/15E148 Safari/604.1',
|
|
7
|
+
viewport: {
|
|
8
|
+
width: 390,
|
|
9
|
+
height: 844,
|
|
10
|
+
hasTouch: true,
|
|
11
|
+
isMobile: true,
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
id: 'mobile-chrome',
|
|
16
|
+
name: 'Mobile Chrome',
|
|
17
|
+
userAgent: 'Mozilla/5.0 (Linux; Android 14; Pixel 8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Mobile Safari/537.36',
|
|
18
|
+
viewport: {
|
|
19
|
+
width: 412,
|
|
20
|
+
height: 915,
|
|
21
|
+
hasTouch: true,
|
|
22
|
+
isMobile: true,
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
];
|
|
26
|
+
}
|
|
27
|
+
export function evaluateWalletCheckoutSmokeSnapshot(snapshot) {
|
|
28
|
+
const failures = [];
|
|
29
|
+
if (!snapshot.subscriptionRequestSucceeded) {
|
|
30
|
+
failures.push('subscription checkout session request did not succeed');
|
|
31
|
+
}
|
|
32
|
+
if (snapshot.walletSlotState === 'unknown') {
|
|
33
|
+
failures.push('wallet slot never reached Stripe readiness or known unavailable state');
|
|
34
|
+
}
|
|
35
|
+
if (!snapshot.cardFallbackVisible) {
|
|
36
|
+
failures.push('card fallback checkout is not visible');
|
|
37
|
+
}
|
|
38
|
+
if (snapshot.blockingOverlayVisible) {
|
|
39
|
+
failures.push('a blocking loader or modal is still visible');
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
ok: failures.length === 0,
|
|
43
|
+
failures,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
export async function runWalletCheckoutSmokeTest(chromium, options) {
|
|
47
|
+
var _a, _b, _c;
|
|
48
|
+
const profiles = (_a = options.profiles) !== null && _a !== void 0 ? _a : buildWalletCheckoutSmokeProfiles();
|
|
49
|
+
const timeoutMs = (_b = options.timeoutMs) !== null && _b !== void 0 ? _b : 15000;
|
|
50
|
+
const subscriptionRequestPath = (_c = options.subscriptionRequestPath) !== null && _c !== void 0 ? _c : '/sdk/public/payments/subscriptions';
|
|
51
|
+
const browser = await chromium.launch({ headless: true });
|
|
52
|
+
try {
|
|
53
|
+
const results = [];
|
|
54
|
+
for (const profile of profiles) {
|
|
55
|
+
const context = await browser.newContext({
|
|
56
|
+
hasTouch: profile.viewport.hasTouch,
|
|
57
|
+
isMobile: profile.viewport.isMobile,
|
|
58
|
+
userAgent: profile.userAgent,
|
|
59
|
+
viewport: {
|
|
60
|
+
width: profile.viewport.width,
|
|
61
|
+
height: profile.viewport.height,
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
try {
|
|
65
|
+
const page = await context.newPage();
|
|
66
|
+
const subscriptionResponse = page
|
|
67
|
+
.waitForResponse((response) => response.url().includes(subscriptionRequestPath) &&
|
|
68
|
+
response.status() >= 200 &&
|
|
69
|
+
response.status() < 300, { timeout: timeoutMs })
|
|
70
|
+
.then(() => true)
|
|
71
|
+
.catch(() => false);
|
|
72
|
+
await page.goto(options.url, { waitUntil: 'domcontentloaded' });
|
|
73
|
+
await page.waitForLoadState('networkidle', { timeout: timeoutMs }).catch(() => undefined);
|
|
74
|
+
const walletSlotResolved = await Promise.race([
|
|
75
|
+
page.waitForSelector(`${options.selectors.walletSlot}.has-express-checkout`, {
|
|
76
|
+
timeout: timeoutMs,
|
|
77
|
+
}).then(() => 'ready'),
|
|
78
|
+
page.waitForSelector(options.selectors.walletSlot, {
|
|
79
|
+
state: 'detached',
|
|
80
|
+
timeout: timeoutMs,
|
|
81
|
+
}).then(() => 'unavailable'),
|
|
82
|
+
]).catch(() => 'unknown');
|
|
83
|
+
const snapshot = {
|
|
84
|
+
blockingOverlayVisible: options.selectors.blockingOverlay
|
|
85
|
+
? await page.isVisible(options.selectors.blockingOverlay, { timeout: 500 }).catch(() => false)
|
|
86
|
+
: false,
|
|
87
|
+
cardFallbackVisible: await page
|
|
88
|
+
.isVisible(options.selectors.cardFallback, { timeout: timeoutMs })
|
|
89
|
+
.catch(() => false),
|
|
90
|
+
subscriptionRequestSucceeded: await subscriptionResponse,
|
|
91
|
+
walletSlotState: walletSlotResolved,
|
|
92
|
+
};
|
|
93
|
+
const evaluation = evaluateWalletCheckoutSmokeSnapshot(snapshot);
|
|
94
|
+
if (snapshot.cardFallbackVisible) {
|
|
95
|
+
await page.click(options.selectors.cardFallback, { timeout: timeoutMs }).catch(() => undefined);
|
|
96
|
+
}
|
|
97
|
+
results.push(Object.assign(Object.assign({}, evaluation), { profileId: profile.id, snapshot }));
|
|
98
|
+
}
|
|
99
|
+
finally {
|
|
100
|
+
await context.close();
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
ok: results.every((result) => result.ok),
|
|
105
|
+
results,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
finally {
|
|
109
|
+
await browser.close();
|
|
110
|
+
}
|
|
111
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@funnelsgrove/payments",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.35",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"private": false,
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -23,10 +23,11 @@
|
|
|
23
23
|
"build": "rm -rf dist && tsc -p tsconfig.build.json && node ../../scripts/fix-esm-relative-imports.mjs dist",
|
|
24
24
|
"lint": "eslint .",
|
|
25
25
|
"prepublishOnly": "npm run build",
|
|
26
|
+
"smoke:wallet": "npm run build && node scripts/wallet-checkout-smoke.mjs",
|
|
26
27
|
"test:run": "vitest run --passWithNoTests"
|
|
27
28
|
},
|
|
28
29
|
"dependencies": {
|
|
29
|
-
"@funnelsgrove/runtime": "0.1.
|
|
30
|
+
"@funnelsgrove/runtime": "^0.1.18",
|
|
30
31
|
"@stripe/react-stripe-js": "^5.6.0",
|
|
31
32
|
"@stripe/stripe-js": "^8.7.0",
|
|
32
33
|
"react": "19.2.3",
|