Skip to content

Commit

Permalink
Merge pull request #13670 from mozilla/FXA-5481
Browse files Browse the repository at this point in the history
feat(payments): autofill coupon when valid query string parameter is provided
  • Loading branch information
sardesam authored Jul 28, 2022
2 parents 02daee3 + 725739b commit a3624ab
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -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(
<AppContext.Provider
value={{
...defaultAppContext,
queryParams: { coupon: 'IDCLEV19' },
}}
>
<CouponForm
planId={SELECTED_PLAN.plan_id}
coupon={undefined}
setCoupon={() => {}}
readOnly={false}
subscriptionInProgress={false}
/>
</AppContext.Provider>
);
};

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(
<AppContext.Provider
value={{
...defaultAppContext,
queryParams: { coupon: 'THECAKEISALIE' },
}}
>
<CouponForm
planId={SELECTED_PLAN.plan_id}
coupon={undefined}
setCoupon={() => {}}
readOnly={false}
subscriptionInProgress={false}
/>
</AppContext.Provider>
);
};

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', () => {
Expand Down
24 changes: 24 additions & 0 deletions packages/fxa-payments-server/src/components/CouponForm/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import React, {
useCallback,
useEffect,
useState,
useContext,
} from 'react';

import {
Expand All @@ -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) {
Expand Down Expand Up @@ -107,8 +109,30 @@ export const CouponForm = ({
);
const [error, setError] = useState<CouponErrorMessageType | null>(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]);
Expand Down
1 change: 1 addition & 0 deletions packages/fxa-payments-server/src/lib/types.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export interface QueryParams {
plan?: string;
coupon?: string;
device_id?: string;
flow_id?: string;
flow_begin_time?: number;
Expand Down

0 comments on commit a3624ab

Please sign in to comment.