@funnelsgrove/cli 0.1.68 → 0.1.71
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/funnel-contract-compatibility.json +46 -46
- package/package.json +4 -4
- package/template_docs/.funnelsgrove-docs.json +9 -9
- package/template_docs/docs/funnelsgrove/contracts/analytics-events.md +2 -1
- package/template_docs/docs/funnelsgrove/contracts/payments.md +6 -1
- package/template_docs/docs/funnelsgrove/migrations/step-contract-v3.md +1 -1
- package/template_docs/docs/funnelsgrove/qa/analytics.md +4 -0
- package/template_docs/docs/funnelsgrove/qa/paywall-checkout.md +3 -0
- package/template_docs/docs/funnelsgrove/steps/paywall_offer.md +4 -2
- package/template_docs/docs/funnelsgrove/steps/upsell_offer.md +3 -2
- package/template_docs/funnel-docs.config.json +1 -1
- package/template_scaffold/.funnelsgrove-docs.json +9 -9
- package/template_scaffold/.funnelsgrove-scaffold.json +16 -16
- package/template_scaffold/docs/funnelsgrove/contracts/analytics-events.md +2 -1
- package/template_scaffold/docs/funnelsgrove/contracts/payments.md +6 -1
- package/template_scaffold/docs/funnelsgrove/migrations/step-contract-v3.md +1 -1
- package/template_scaffold/docs/funnelsgrove/qa/analytics.md +4 -0
- package/template_scaffold/docs/funnelsgrove/qa/paywall-checkout.md +3 -0
- package/template_scaffold/docs/funnelsgrove/steps/paywall_offer.md +4 -2
- package/template_scaffold/docs/funnelsgrove/steps/upsell_offer.md +3 -2
- package/template_scaffold/funnel-docs.config.json +1 -1
- package/template_scaffold/package-lock.json +15 -15
- package/template_scaffold/package.json +3 -3
- package/template_scaffold/src/steps/step-32-paywall.tsx +89 -106
- package/template_scaffold/tests/funnel-agent-docs.test.ts +1 -1
- package/template_scaffold/tests/src/steps/step-32-paywall.test.ts +37 -51
|
@@ -43,8 +43,7 @@ describe('ClaimBee paywall source', () => {
|
|
|
43
43
|
);
|
|
44
44
|
|
|
45
45
|
expect(stepSource).toContain('SharedCheckoutSpecialOfferDialog');
|
|
46
|
-
expect(stepSource).toContain('
|
|
47
|
-
expect(stepSource).toContain('GooglePaySubscriptionCheckoutSlot');
|
|
46
|
+
expect(stepSource).toContain('StripeSubscriptionWalletSurface');
|
|
48
47
|
expect(stepSource).toContain('SharedStripeCheckoutV2Dialog');
|
|
49
48
|
expect(stepSource).not.toContain('StripeExpressCheckoutElement');
|
|
50
49
|
expect(stepSource).not.toContain('createStripeSubscriptionCheckout');
|
|
@@ -67,8 +66,8 @@ describe('ClaimBee paywall source', () => {
|
|
|
67
66
|
expect(stepSource).toContain('imageSrc={content.checkout.specialOffer.image.src}');
|
|
68
67
|
expect(stepSource).toContain("className='paywall-v2-scroll-cta paywall-v2-vibe-cta'");
|
|
69
68
|
expect(stepSource).toContain("className='paywall-v2-card-button paywall-v2-vibe-cta'");
|
|
70
|
-
expect(stepSource).toContain("
|
|
71
|
-
expect(stepSource).toContain("
|
|
69
|
+
expect(stepSource).toContain("applePay: 'paywall-v2-apple-pay-button'");
|
|
70
|
+
expect(stepSource).toContain("googlePay: 'paywall-v2-google-pay-button'");
|
|
72
71
|
expect(stepSource).not.toContain('Continue with other payment options');
|
|
73
72
|
});
|
|
74
73
|
|
|
@@ -172,7 +171,7 @@ describe('ClaimBee paywall source', () => {
|
|
|
172
171
|
expect(stepSource).toContain('useStripeSubscriptionCheckoutSession');
|
|
173
172
|
expect(stepSource).toContain('checkoutSession.activeClientSecret');
|
|
174
173
|
expect(stepSource).toContain('<SharedStripeCheckoutV2Dialog');
|
|
175
|
-
expect(stepSource).toContain('<
|
|
174
|
+
expect(stepSource).toContain('<StripeSubscriptionWalletSurface');
|
|
176
175
|
expect(stepSource).not.toContain('<StripeExpressCheckoutElement');
|
|
177
176
|
expect(stepSource).not.toContain('createStripePaymentIntent');
|
|
178
177
|
expect(stepSource).not.toContain('createStripeSubscriptionCheckout');
|
|
@@ -183,23 +182,25 @@ describe('ClaimBee paywall source', () => {
|
|
|
183
182
|
expect(stepSource).toContain("aria-label='Loading checkout'");
|
|
184
183
|
});
|
|
185
184
|
|
|
186
|
-
it('claims paywall completion only
|
|
185
|
+
it('claims paywall completion only after verified checkout success', () => {
|
|
187
186
|
const stepSource = readFileSync(
|
|
188
187
|
path.resolve(__dirname, '../../../src/steps/step-32-paywall.tsx'),
|
|
189
188
|
'utf8',
|
|
190
189
|
);
|
|
191
|
-
const
|
|
192
|
-
stepSource.indexOf('const
|
|
190
|
+
const completionHandler = stepSource.slice(
|
|
191
|
+
stepSource.indexOf('const handleCheckoutCompleted = () => {'),
|
|
193
192
|
stepSource.indexOf('const preparePaywallWalletCheckout'),
|
|
194
193
|
);
|
|
195
194
|
const checkoutStartHandler = stepSource.slice(
|
|
196
195
|
stepSource.indexOf('const startCheckout = async () => {'),
|
|
197
|
-
stepSource.indexOf('const
|
|
196
|
+
stepSource.indexOf('const handleCheckoutCompleted'),
|
|
198
197
|
);
|
|
199
198
|
|
|
200
199
|
expect(stepSource).toContain('const { user, setUser, attributes, featureFlags, completeStep } = useFunnel();');
|
|
201
|
-
expect(
|
|
202
|
-
expect(
|
|
200
|
+
expect(completionHandler).toContain('completeStep(analyticsStepId, {');
|
|
201
|
+
expect(completionHandler).toContain('planId: selectedDisplayPlan.id');
|
|
202
|
+
expect(stepSource).toContain('onSuccess={handleCheckoutCompleted}');
|
|
203
|
+
expect(stepSource).not.toContain('onPaymentInfoSubmitted=');
|
|
203
204
|
expect(checkoutStartHandler).not.toContain('completeStep(');
|
|
204
205
|
});
|
|
205
206
|
|
|
@@ -315,8 +316,7 @@ describe('ClaimBee paywall source', () => {
|
|
|
315
316
|
expect(plansIndex).toBeGreaterThan(-1);
|
|
316
317
|
expect(paymentStackIndex).toBeGreaterThan(plansIndex);
|
|
317
318
|
expect(featureGridIndex).toBeGreaterThan(paymentStackIndex);
|
|
318
|
-
expect(stepSource).toContain('
|
|
319
|
-
expect(stepSource).toContain('GooglePaySubscriptionCheckoutSlot');
|
|
319
|
+
expect(stepSource).toContain('StripeSubscriptionWalletSurface');
|
|
320
320
|
expect(stepSource).toContain('.paywall-v2-apple-pay-button,');
|
|
321
321
|
expect(stepSource).toContain('.paywall-v2-google-pay-button {');
|
|
322
322
|
expect(stepSource).toContain('min-height: 64px;');
|
|
@@ -352,12 +352,13 @@ describe('ClaimBee paywall source', () => {
|
|
|
352
352
|
'utf8',
|
|
353
353
|
);
|
|
354
354
|
|
|
355
|
-
expect(stepSource).toContain(
|
|
356
|
-
expect(stepSource).toContain("
|
|
357
|
-
expect(stepSource).toContain('
|
|
358
|
-
expect(stepSource).toContain('
|
|
355
|
+
expect(stepSource).toContain('<StripeSubscriptionWalletSurface');
|
|
356
|
+
expect(stepSource).toContain("surfaceId={PAYWALL_WALLET_SURFACE_ID}");
|
|
357
|
+
expect(stepSource).toContain('checkout={walletCheckoutInput}');
|
|
358
|
+
expect(stepSource).toContain('resolveMethodClassName={resolvePaywallWalletMethodClassName}');
|
|
359
|
+
expect(stepSource).toContain('resolveMethodWrapperClassName={resolvePaywallWalletMethodWrapperClassName}');
|
|
359
360
|
expect(stepSource).toContain('onUnavailableClick={openCardCheckoutFromUnavailableWallet}');
|
|
360
|
-
expect(stepSource).toContain('session={checkoutSession}');
|
|
361
|
+
expect(stepSource).not.toContain('session={checkoutSession}');
|
|
361
362
|
expect(stepSource).not.toContain('onClick={() => void startWalletCheckout()}');
|
|
362
363
|
expect(stepSource).not.toContain('StripeExpressCheckoutElement');
|
|
363
364
|
expect(stepSource).not.toContain('createStripeSubscriptionCheckout');
|
|
@@ -372,14 +373,13 @@ describe('ClaimBee paywall source', () => {
|
|
|
372
373
|
'utf8',
|
|
373
374
|
);
|
|
374
375
|
|
|
375
|
-
expect(stepSource).toContain('type PaywallWalletAvailabilityState =
|
|
376
|
-
expect(stepSource).toContain('
|
|
377
|
-
expect(stepSource).toContain(
|
|
378
|
-
expect(stepSource).toContain(
|
|
379
|
-
expect(stepSource).toContain('
|
|
376
|
+
expect(stepSource).toContain('type PaywallWalletAvailabilityState = Partial<Record<string, boolean>>;');
|
|
377
|
+
expect(stepSource).toContain('useState<PaywallWalletAvailabilityState>({});');
|
|
378
|
+
expect(stepSource).toContain('const handleWalletSurfaceAvailabilityChange = (');
|
|
379
|
+
expect(stepSource).toContain('availability: StripeSubscriptionWalletSurfaceAvailability');
|
|
380
|
+
expect(stepSource).toContain('paywallWalletAvailability[PAYWALL_WALLET_SURFACE_ID] ?? null');
|
|
380
381
|
expect(stepSource).toContain('initialWalletAvailable={checkoutInitialWalletAvailable}');
|
|
381
|
-
expect(stepSource).toContain('
|
|
382
|
-
expect(stepSource).toContain('onAvailabilityChange={handleGooglePayAvailabilityChange}');
|
|
382
|
+
expect(stepSource).toContain('handleWalletSurfaceAvailabilityChange(PAYWALL_WALLET_SURFACE_ID, availability)');
|
|
383
383
|
});
|
|
384
384
|
|
|
385
385
|
it('prepares the real Apple Pay element on load instead of waiting for the placeholder tap', () => {
|
|
@@ -389,7 +389,7 @@ describe('ClaimBee paywall source', () => {
|
|
|
389
389
|
);
|
|
390
390
|
|
|
391
391
|
expect(stepSource).toContain('useStripeSubscriptionCheckoutSession');
|
|
392
|
-
expect(stepSource).toContain('
|
|
392
|
+
expect(stepSource).toContain('StripeSubscriptionWalletSurface');
|
|
393
393
|
expect(stepSource).toContain('checkoutSession.prepareCardCheckout');
|
|
394
394
|
expect(stepSource).toContain('checkoutSession.activeClientSecret');
|
|
395
395
|
expect(stepSource).not.toContain('const autoWalletIntentKeyRef = useRef<string | null>(null);');
|
|
@@ -410,8 +410,8 @@ describe('ClaimBee paywall source', () => {
|
|
|
410
410
|
expect(stepSource).toContain('couponId: checkoutPromoActive ? selectedDisplayPlan?.couponId ?? null : null');
|
|
411
411
|
expect(stepSource).toContain('summaryLabel: checkoutSummaryLabel');
|
|
412
412
|
expect(stepSource).toContain('checkoutSession.activeClientSecret');
|
|
413
|
-
expect(stepSource).toContain('<
|
|
414
|
-
expect(stepSource).toContain('<
|
|
413
|
+
expect(stepSource).toContain('<StripeSubscriptionWalletSurface');
|
|
414
|
+
expect(stepSource).toContain('const walletCheckoutInput = useMemo<StripeSubscriptionWalletSurfaceCheckoutInput>');
|
|
415
415
|
expect(stepSource).not.toContain('StripeExpressCheckoutElement');
|
|
416
416
|
expect(stepSource).not.toContain('preparePaywallWalletSubscription');
|
|
417
417
|
expect(stepSource).not.toContain('const handlePaywallApplePayPlaceholderClick = () => {');
|
|
@@ -424,9 +424,8 @@ describe('ClaimBee paywall source', () => {
|
|
|
424
424
|
'utf8',
|
|
425
425
|
);
|
|
426
426
|
|
|
427
|
-
expect(stepSource).toContain('
|
|
427
|
+
expect(stepSource).not.toContain('publicAnalyticsSdk');
|
|
428
428
|
expect(stepSource).not.toContain('publicAnalyticsSdk.trackCheckoutStarted({');
|
|
429
|
-
expect(stepSource).toContain('publicAnalyticsSdk.trackPaymentInfoSubmitted({');
|
|
430
429
|
expect(stepSource).toContain('stepType: stepPaywall.type');
|
|
431
430
|
expect(stepSource).toContain('value: selectedDisplayPlan.analyticsPurchaseValue');
|
|
432
431
|
expect(stepSource).toContain("currency: 'USD'");
|
|
@@ -434,16 +433,16 @@ describe('ClaimBee paywall source', () => {
|
|
|
434
433
|
expect(stepSource).toContain('const checkoutAnalyticsContext = useMemo(');
|
|
435
434
|
expect(stepSource).toContain('checkoutAnalytics={checkoutAnalyticsContext}');
|
|
436
435
|
expect(stepSource).toContain('checkoutSessionId={checkoutSession.checkoutSessionId}');
|
|
437
|
-
expect(stepSource).toContain('onPaymentInfoSubmitted=
|
|
436
|
+
expect(stepSource).not.toContain('onPaymentInfoSubmitted=');
|
|
438
437
|
expect(stepSource).toContain("await checkoutSession.prepareCardCheckout({ checkoutStartSource: 'checkout_render' });");
|
|
439
|
-
expect(stepSource).
|
|
438
|
+
expect(stepSource).toContain('const handleCheckoutCompleted = () => {');
|
|
440
439
|
expect(stepSource).not.toContain('publicAnalyticsSdk.trackCheckoutCompleted({');
|
|
441
|
-
expect(stepSource).
|
|
440
|
+
expect(stepSource).toContain('onSuccess={handleCheckoutCompleted}');
|
|
442
441
|
expect(stepSource).not.toContain("eventType: 'checkout_started'");
|
|
443
442
|
expect(stepSource).not.toContain("eventType: 'checkout_completed'");
|
|
444
443
|
});
|
|
445
444
|
|
|
446
|
-
it('
|
|
445
|
+
it('delegates payment-info analytics to shared checkout components with session context', () => {
|
|
447
446
|
const stepSource = readFileSync(
|
|
448
447
|
path.resolve(__dirname, '../../../src/steps/step-32-paywall.tsx'),
|
|
449
448
|
'utf8',
|
|
@@ -456,25 +455,12 @@ describe('ClaimBee paywall source', () => {
|
|
|
456
455
|
stepSource.indexOf('const checkoutAnalyticsContext = useMemo(() => {'),
|
|
457
456
|
stepSource.indexOf('const successReturnUrl = useMemo(() => {'),
|
|
458
457
|
);
|
|
459
|
-
const paymentInfoHandler = stepSource.slice(
|
|
460
|
-
stepSource.indexOf('const trackPaymentInfoSubmitted = () => {'),
|
|
461
|
-
stepSource.indexOf('const preparePaywallWalletCheckout'),
|
|
462
|
-
);
|
|
463
|
-
|
|
464
458
|
expect(analyticsMetadata).toContain("currency: 'USD'");
|
|
465
459
|
expect(checkoutAnalyticsContext).toContain('metadata: checkoutAnalyticsMetadata');
|
|
466
|
-
expect(
|
|
467
|
-
|
|
468
|
-
);
|
|
469
|
-
expect(
|
|
470
|
-
expect(paymentInfoHandler.indexOf('if (!checkoutSessionId) {')).toBeLessThan(
|
|
471
|
-
paymentInfoHandler.indexOf('completeStep(analyticsStepId, {'),
|
|
472
|
-
);
|
|
473
|
-
expect(paymentInfoHandler).toContain(
|
|
474
|
-
'eventId: `add_payment_info:${checkoutSessionId}`',
|
|
475
|
-
);
|
|
476
|
-
expect(paymentInfoHandler).toContain('metadata: checkoutAnalyticsMetadata');
|
|
477
|
-
expect(paymentInfoHandler).toContain('void publicAnalyticsSdk.flush().catch(() => 0);');
|
|
460
|
+
expect(stepSource.match(/checkoutAnalytics=\{checkoutAnalyticsContext\}/g)).toHaveLength(2);
|
|
461
|
+
expect(stepSource).toContain('checkoutSessionId={checkoutSession.checkoutSessionId}');
|
|
462
|
+
expect(stepSource).not.toContain('trackPaymentInfoSubmitted');
|
|
463
|
+
expect(stepSource).not.toContain('add_payment_info:');
|
|
478
464
|
});
|
|
479
465
|
|
|
480
466
|
it('uses a local three-plan catalog so the paywall shows weekly, monthly, and yearly offers', () => {
|