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;