mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2025-12-19 18:18:27 -05:00
feat(client): add 25 dollar tier ab test (#62014)
This commit is contained in:
@@ -30,6 +30,32 @@
|
||||
"name": "tests the conversion rate of the new design comparing to the old one"
|
||||
}
|
||||
]
|
||||
},
|
||||
"replace-20-with-25": {
|
||||
"defaultValue": false,
|
||||
"rules": [
|
||||
{
|
||||
"coverage": 1,
|
||||
"hashAttribute": "id",
|
||||
"seed": "replace-20-with-25",
|
||||
"hashVersion": 2,
|
||||
"variations": [false, true],
|
||||
"weights": [0.5, 0.5],
|
||||
"key": "replace-20-with-25",
|
||||
"meta": [
|
||||
{
|
||||
"key": "0",
|
||||
"name": "Control"
|
||||
},
|
||||
{
|
||||
"key": "1",
|
||||
"name": "Variation 1"
|
||||
}
|
||||
],
|
||||
"phase": "0",
|
||||
"name": "stg replace 20 with 25"
|
||||
}
|
||||
]
|
||||
},
|
||||
"show-modal-randomly": {
|
||||
"defaultValue": false,
|
||||
|
||||
@@ -14,7 +14,9 @@ import { useTranslation } from 'react-i18next';
|
||||
import {
|
||||
PaymentContext,
|
||||
subscriptionAmounts,
|
||||
subscriptionAmountsB,
|
||||
defaultTierAmount,
|
||||
defaultTierAmountB,
|
||||
type DonationAmount
|
||||
} from '../../../../shared/config/donation-settings'; // You can further extract these into separate components and import them
|
||||
import callGA from '../../analytics/call-ga';
|
||||
@@ -42,6 +44,10 @@ function SelectionTabs({
|
||||
isAnimationEnabled?: boolean;
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const replace20With25 = useFeature('replace-20-with-25').on;
|
||||
const activeSubscriptionAmounts = replace20With25
|
||||
? subscriptionAmountsB
|
||||
: subscriptionAmounts;
|
||||
const switchTab = (value: string): void => {
|
||||
setDonationAmount(Number(value) as DonationAmount);
|
||||
};
|
||||
@@ -81,7 +87,7 @@ function SelectionTabs({
|
||||
onValueChange={switchTab}
|
||||
>
|
||||
<TabsList className='nav-lists'>
|
||||
{subscriptionAmounts.map(value => (
|
||||
{activeSubscriptionAmounts.map(value => (
|
||||
<TabsTrigger
|
||||
key={value}
|
||||
value={value.toString()}
|
||||
@@ -92,7 +98,7 @@ function SelectionTabs({
|
||||
))}
|
||||
</TabsList>
|
||||
<Spacer size='xs' />
|
||||
{subscriptionAmounts.map(value => {
|
||||
{activeSubscriptionAmounts.map(value => {
|
||||
const usd = formattedAmountLabel(donationAmount);
|
||||
const hours = convertToTimeContributed(donationAmount);
|
||||
const donationDescription = t('donate.your-donation-2', {
|
||||
@@ -169,7 +175,10 @@ const MultiTierDonationForm: React.FC<MultiTierDonationFormProps> = ({
|
||||
paymentContext,
|
||||
isAnimationEnabled
|
||||
}) => {
|
||||
const [donationAmount, setDonationAmount] = useState(defaultTierAmount);
|
||||
const replace20With25 = useFeature('replace-20-with-25').on;
|
||||
const [donationAmount, setDonationAmount] = useState(
|
||||
replace20With25 ? defaultTierAmountB : defaultTierAmount
|
||||
);
|
||||
|
||||
const [showDonateForm, setShowDonateForm] = useState(false);
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
import translations from '../client/i18n/locales/english/translations.json';
|
||||
import { addGrowthbookCookie } from './utils/add-growthbook-cookie';
|
||||
|
||||
const pageElements = {
|
||||
mainHeading: 'main-head',
|
||||
@@ -16,10 +17,14 @@ const donationStringReplacements = {
|
||||
};
|
||||
|
||||
const donationFormStrings = {
|
||||
conformTwentyDollar: translations.donate['confirm-monthly'].replace(
|
||||
confirmTwentyDollar: translations.donate['confirm-monthly'].replace(
|
||||
donationStringReplacements.usdPlaceHolder,
|
||||
'20'
|
||||
),
|
||||
confirmTwentyFiveDollar: translations.donate['confirm-monthly'].replace(
|
||||
donationStringReplacements.usdPlaceHolder,
|
||||
'25'
|
||||
),
|
||||
confirmFiveDollars: translations.donate['confirm-monthly'].replace(
|
||||
donationStringReplacements.usdPlaceHolder,
|
||||
'5'
|
||||
@@ -27,6 +32,9 @@ const donationFormStrings = {
|
||||
twentyDollarsLearningContribution: translations.donate['your-donation-2']
|
||||
.replace(donationStringReplacements.usdPlaceHolder, '20')
|
||||
.replace(donationStringReplacements.hoursPlaceHolder, '1,000'),
|
||||
twentyFiveDollarsLearningContribution: translations.donate['your-donation-2']
|
||||
.replace(donationStringReplacements.usdPlaceHolder, '25')
|
||||
.replace(donationStringReplacements.hoursPlaceHolder, '1,250'),
|
||||
fiveDollarsLearningContribution: translations.donate['your-donation-2']
|
||||
.replace(donationStringReplacements.usdPlaceHolder, '5')
|
||||
.replace(donationStringReplacements.hoursPlaceHolder, '250'),
|
||||
@@ -213,31 +221,6 @@ function donatePageTests() {
|
||||
await faq12.click();
|
||||
});
|
||||
|
||||
test('should select $20 tier by default', async ({ page }) => {
|
||||
await expect(
|
||||
page.getByText(donationFormStrings.conformTwentyDollar)
|
||||
).toBeVisible();
|
||||
|
||||
const tabs = await page.$$('[role="tab"]');
|
||||
expect(tabs.length).toBe(4);
|
||||
|
||||
for (const tab of tabs) {
|
||||
const tabText = await tab.innerText();
|
||||
expect(['$5', '$10', '$20', '$40']).toContain(tabText);
|
||||
|
||||
if (tabText === '$20') {
|
||||
const isActive = await tab.getAttribute('data-state');
|
||||
expect(isActive).toBe('active');
|
||||
} else {
|
||||
const isActive = await tab.getAttribute('data-state');
|
||||
expect(isActive).not.toBe('active');
|
||||
}
|
||||
}
|
||||
await expect(
|
||||
page.getByText(donationFormStrings.twentyDollarsLearningContribution)
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
test('should make $5 tier selectable', async ({ page }) => {
|
||||
await page.click('[role="tab"]:has-text("$5")');
|
||||
|
||||
@@ -281,6 +264,33 @@ function donatePageTests() {
|
||||
});
|
||||
}
|
||||
|
||||
interface DefaultTierTestConfig {
|
||||
defaultTier: string;
|
||||
tiers: string[];
|
||||
confirmationText: string;
|
||||
contributionText: string;
|
||||
}
|
||||
|
||||
function donatePageDefault(config: DefaultTierTestConfig) {
|
||||
const { defaultTier, tiers, confirmationText, contributionText } = config;
|
||||
test(`should select ${defaultTier} tier by default`, async ({ page }) => {
|
||||
await expect(page.getByText(confirmationText)).toBeVisible();
|
||||
const tabs = await page.$$('[role="tab"]');
|
||||
expect(tabs.length).toBe(tiers.length);
|
||||
for (const tab of tabs) {
|
||||
const tabText = await tab.innerText();
|
||||
expect(tiers).toContain(tabText);
|
||||
const isActive = await tab.getAttribute('data-state');
|
||||
if (tabText === defaultTier) {
|
||||
expect(isActive).toBe('active');
|
||||
} else {
|
||||
expect(isActive).not.toBe('active');
|
||||
}
|
||||
}
|
||||
await expect(page.getByText(contributionText)).toBeVisible();
|
||||
});
|
||||
}
|
||||
|
||||
test.describe('Authenticated User', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/donate');
|
||||
@@ -288,6 +298,19 @@ test.describe('Authenticated User', () => {
|
||||
donatePageTests();
|
||||
});
|
||||
|
||||
test.describe('Authenticated User Page Defaults - Variation A', () => {
|
||||
test.beforeEach(async ({ context, page }) => {
|
||||
await addGrowthbookCookie({ context, variation: 'A243' });
|
||||
await page.goto('/donate');
|
||||
});
|
||||
donatePageDefault({
|
||||
defaultTier: '$20',
|
||||
tiers: ['$5', '$10', '$20', '$40'],
|
||||
confirmationText: donationFormStrings.confirmTwentyDollar,
|
||||
contributionText: donationFormStrings.twentyDollarsLearningContribution
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Unauthenticated User', () => {
|
||||
test.use({ storageState: { cookies: [], origins: [] } });
|
||||
test.beforeEach(async ({ page }) => {
|
||||
@@ -295,3 +318,17 @@ test.describe('Unauthenticated User', () => {
|
||||
});
|
||||
donatePageTests();
|
||||
});
|
||||
|
||||
test.describe('Unauthenticated User Page Default - Variation B', () => {
|
||||
test.use({ storageState: { cookies: [], origins: [] } });
|
||||
test.beforeEach(async ({ context, page }) => {
|
||||
await addGrowthbookCookie({ context, variation: 'B145' });
|
||||
await page.goto('/donate');
|
||||
});
|
||||
donatePageDefault({
|
||||
defaultTier: '$25',
|
||||
tiers: ['$5', '$10', '$25', '$40'],
|
||||
confirmationText: donationFormStrings.confirmTwentyFiveDollar,
|
||||
contributionText: donationFormStrings.twentyFiveDollarsLearningContribution
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Configuration for client side
|
||||
|
||||
export type DonationAmount = 500 | 1000 | 2000 | 4000;
|
||||
export type DonationAmount = 500 | 1000 | 2000 | 2500 | 4000;
|
||||
export type DonationDuration = 'one-time' | 'month';
|
||||
export interface DonationConfig {
|
||||
donationAmount: DonationAmount;
|
||||
@@ -8,6 +8,7 @@ export interface DonationConfig {
|
||||
}
|
||||
|
||||
export const subscriptionAmounts: DonationAmount[] = [500, 1000, 2000, 4000];
|
||||
export const subscriptionAmountsB: DonationAmount[] = [500, 1000, 2500, 4000];
|
||||
|
||||
export const defaultDonation: DonationConfig = {
|
||||
donationAmount: 500,
|
||||
@@ -15,6 +16,7 @@ export const defaultDonation: DonationConfig = {
|
||||
};
|
||||
|
||||
export const defaultTierAmount: DonationAmount = 2000;
|
||||
export const defaultTierAmountB: DonationAmount = 2500;
|
||||
|
||||
export const onetimeSKUConfig = {
|
||||
production: [
|
||||
@@ -53,6 +55,7 @@ export const paypalConfigTypes = {
|
||||
500: { planId: 'P-6B636789V3105190KMTJFH7A' },
|
||||
1000: { planId: 'P-53P76823N8780520DMVTWF3I' },
|
||||
2000: { planId: 'P-8HY47434FB9663500MVTWFOA' },
|
||||
2500: { planId: 'P-1E758922LA293854BNC3SK3A' },
|
||||
3000: { planId: 'P-1KY930839N8045117L6E4BKY' },
|
||||
4000: { planId: 'P-0MH28916302828423MVTWEBI' },
|
||||
5000: { planId: 'P-0WR49877YD949401BL6E4CTA' }
|
||||
@@ -63,6 +66,7 @@ export const paypalConfigTypes = {
|
||||
500: { planId: 'P-37N14480BW163382FLZYPVMA' },
|
||||
1000: { planId: 'P-28B62039J8092810UL6E3FXA' },
|
||||
2000: { planId: 'P-7HR706961M9170433L6HI5VI' },
|
||||
2500: { planId: 'P-2BK29709FB733490FNC3RPGQ' },
|
||||
3000: { planId: 'P-35V33574BU596924JL6HI6XY' },
|
||||
4000: { planId: 'P-45M45060289267734L6HJSXA' },
|
||||
5000: { planId: 'P-0MD70861FY4172444L6HJTUQ' }
|
||||
@@ -90,6 +94,7 @@ export const paypalConfigurator = (
|
||||
500: { planId: string };
|
||||
1000: { planId: string };
|
||||
2000: { planId: string };
|
||||
2500: { planId: string };
|
||||
3000: { planId: string };
|
||||
4000: { planId: string };
|
||||
5000: { planId: string };
|
||||
@@ -130,6 +135,7 @@ const stripeProductIds = {
|
||||
500: 'prod_Cc9bIxB2NvjpLy',
|
||||
1000: 'prod_BuiSxWk7jGSFlJ',
|
||||
2000: 'prod_IElpZVK7kOn6Fe',
|
||||
2500: 'prod_JCakZSxh12ZaDF',
|
||||
4000: 'prod_IElq1foW39g3Cx'
|
||||
}
|
||||
},
|
||||
@@ -138,6 +144,7 @@ const stripeProductIds = {
|
||||
500: 'prod_GD1GGbJsqQaupl',
|
||||
1000: 'prod_GD1IzNEXfSCGgy',
|
||||
2000: 'prod_IEkNp8M03xvsuB',
|
||||
2500: 'prod_T12UtcRPvzzVN1',
|
||||
4000: 'prod_IEkPebxS63mVbs'
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user