diff --git a/packages/fxa-payments-server/src/components/CouponForm/index.test.tsx b/packages/fxa-payments-server/src/components/CouponForm/index.test.tsx index 06daba18042..1f311a228f7 100644 --- a/packages/fxa-payments-server/src/components/CouponForm/index.test.tsx +++ b/packages/fxa-payments-server/src/components/CouponForm/index.test.tsx @@ -1,10 +1,17 @@ -import { render, cleanup, fireEvent, waitFor } from '@testing-library/react'; +import { + render, + screen, + cleanup, + fireEvent, + waitFor, +} from '@testing-library/react'; import '@testing-library/jest-dom/extend-expect'; import CouponForm, { checkPromotionCode, CouponErrorMessageType, } from './index'; import { CouponDetails } from 'fxa-shared/dto/auth/payments/coupon'; +import { defaultAppContext, AppContext } from '../../lib/AppContext'; import { COUPON_DETAILS_EXPIRED, COUPON_DETAILS_INVALID, @@ -216,6 +223,89 @@ describe('CouponForm', () => { const removeButton = queryByTestId('coupon-remove-button'); expect(removeButton).toBeDisabled(); }); + + it('shows the coupon code if valid coupon code was passed in query string', async () => { + const coupon: CouponDetails = { + discountAmount: 200, + promotionCode: 'IDCLEV19', + type: '', + durationInMonths: 1, + valid: true, + expired: false, + maximallyRedeemed: false, + }; + + (apiRetrieveCouponDetails as jest.Mock) + .mockClear() + .mockResolvedValue(coupon); + + const subject = () => { + return render( + + {}} + readOnly={false} + subscriptionInProgress={false} + /> + + ); + }; + + const { queryByTestId } = subject(); + + // wait for coupon to be applied + await waitFor(() => { + expect(screen.getByText('IDCLEV19')).toBeInTheDocument(); + expect(queryByTestId('coupon-form')).not.toBeInTheDocument(); + expect(queryByTestId('coupon-hascoupon')).toBeInTheDocument(); + }); + }); + + it('renders without a coupon code if invalid coupon code was passed in query string', async () => { + (apiRetrieveCouponDetails as jest.Mock) + .mockClear() + .mockResolvedValue(COUPON_DETAILS_INVALID); + + const subject = () => { + return render( + + {}} + readOnly={false} + subscriptionInProgress={false} + /> + + ); + }; + + const { queryByTestId } = subject(); + + // wait for coupon to be checked + await waitFor(() => { + expect(screen.queryByText('THECAKEISALIE')).not.toBeInTheDocument(); + const couponInputField = queryByTestId('coupon-input'); + const couponButton = queryByTestId('coupon-button'); + expect(couponInputField).toBeInTheDocument(); + expect(couponInputField).not.toBeDisabled(); + expect(couponButton).toBeInTheDocument(); + expect(couponButton).not.toBeDisabled(); + expect(couponMounted).toBeCalledTimes(1); + }); + }); }); describe('checkPromotionCode', () => { diff --git a/packages/fxa-payments-server/src/components/CouponForm/index.tsx b/packages/fxa-payments-server/src/components/CouponForm/index.tsx index 9cfb8e7c2d6..9c838b06cd4 100644 --- a/packages/fxa-payments-server/src/components/CouponForm/index.tsx +++ b/packages/fxa-payments-server/src/components/CouponForm/index.tsx @@ -8,6 +8,7 @@ import React, { useCallback, useEffect, useState, + useContext, } from 'react'; import { @@ -20,6 +21,7 @@ import { } from '../../lib/amplitude'; import { APIError, apiRetrieveCouponDetails } from '../../lib/apiClient'; import { useCallbackOnce } from '../../lib/hooks'; +import AppContext from '../../lib/AppContext'; class CouponError extends Error { constructor(message: string) { @@ -107,8 +109,30 @@ export const CouponForm = ({ ); const [error, setError] = useState(null); const [checkingCoupon, setCheckingCoupon] = useState(false); + const { queryParams } = useContext(AppContext); const onFormMounted = useCallback(() => couponMounted({ planId }), [planId]); + + // check if coupon code was included in URL + // if true and valid, apply coupon code on page load + useEffect(() => { + (async () => { + if (queryParams.coupon) { + try { + setCheckingCoupon(true); + const coupon = await checkPromotionCode(planId, queryParams.coupon); + setHasCoupon(true); + setCoupon(coupon); + setPromotionCode(coupon.promotionCode); + } catch (err) { + setCoupon(undefined); + } finally { + setCheckingCoupon(false); + } + } + })(); + }, [queryParams, planId, setCoupon]); + useEffect(() => { onFormMounted(); }, [onFormMounted, planId]); diff --git a/packages/fxa-payments-server/src/lib/types.tsx b/packages/fxa-payments-server/src/lib/types.tsx index 75c90704c63..eecbd046eb1 100644 --- a/packages/fxa-payments-server/src/lib/types.tsx +++ b/packages/fxa-payments-server/src/lib/types.tsx @@ -1,5 +1,6 @@ export interface QueryParams { plan?: string; + coupon?: string; device_id?: string; flow_id?: string; flow_begin_time?: number;