Skip to content

Commit

Permalink
Merge pull request #1344 from guardian/tier-three
Browse files Browse the repository at this point in the history
Add Tier Three product
  • Loading branch information
rupertbates authored Jun 26, 2024
2 parents ff0d24b + e0bc53c commit 16341c0
Show file tree
Hide file tree
Showing 14 changed files with 289 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
supporterPlusAnnualCancelled,
supporterPlusCancelled,
supporterPlusInOfferPeriod,
tierThree,
} from '../../../fixtures/productBuilder/testProducts';
import { singleContributionsAPIResponse } from '../../../fixtures/singleContribution';
import { user } from '../../../fixtures/user';
Expand Down Expand Up @@ -91,6 +92,7 @@ export const WithSubscriptions: StoryObj<typeof AccountOverview> = {
newspaperVoucherPaidByPaypal(),
membershipSupporter(),
supporterPlus(),
tierThree(),
),
),
);
Expand Down Expand Up @@ -223,6 +225,7 @@ export const WithCancelledSubscriptions: StoryObj<typeof AccountOverview> = {
guardianWeeklyCancelled(),
supporterPlusCancelled(),
supporterPlusAnnualCancelled(),
tierThree(),
),
),
);
Expand Down
13 changes: 13 additions & 0 deletions client/components/mma/accountoverview/ManageProduct.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
newspaperVoucherPaidByPaypal,
supporterPlusAnnual,
supporterPlusMonthlyAllAccessDigital,
tierThree,
} from '../../../fixtures/productBuilder/testProducts';
import { ManageProduct } from './ManageProduct';

Expand All @@ -33,6 +34,18 @@ export const GuardianWeekly: StoryObj<typeof ManageProduct> = {
},
};

export const TierThree: StoryObj<typeof ManageProduct> = {
render: () => {
return <ManageProduct productType={PRODUCT_TYPES.tierthree} />;
},

parameters: {
reactRouter: {
state: { productDetail: tierThree() },
},
},
};

export const DigitalSubscription: StoryObj<typeof ManageProduct> = {
render: () => {
return <ManageProduct productType={PRODUCT_TYPES.digipack} />;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { palette } from '@guardian/source/foundations';
import type { ProductTypeKeys } from '../../../../shared/productTypes';
import type { ProductTypeKeys } from '@/shared/productTypes';

export const textColour = {
light: palette.neutral[100],
Expand Down Expand Up @@ -48,6 +48,10 @@ export const productCardConfiguration: {
colour: productColour.supporterPlus,
showBenefitsSection: true,
},
tierthree: {
colour: productColour.supporterPlus,
showBenefitsSection: true,
},
digipack: {
colour: productColour.digital,
},
Expand Down
2 changes: 2 additions & 0 deletions client/components/mma/billing/Billing.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
digitalPackPaidByDirectDebit,
guardianWeeklyPaidByCard,
newspaperVoucherPaidByPaypal,
tierThree,
} from '../../../fixtures/productBuilder/testProducts';
import { user } from '../../../fixtures/user';
import { Billing } from './Billing';
Expand Down Expand Up @@ -71,6 +72,7 @@ export const WithSubscriptions: StoryObj<typeof Billing> = {
guardianWeeklyPaidByCard(),
digitalPackPaidByDirectDebit(),
newspaperVoucherPaidByPaypal(),
tierThree(),
),
),
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,9 @@ const Form = (props: FormProps) => {
)
.flatMap(flattenEquivalent)
.map(({ productDetail }) => {
const friendlyProductName = GROUPED_PRODUCT_TYPES.subscriptions
const friendlyProductName = GROUPED_PRODUCT_TYPES[
productDetail.mmaCategory
]
.mapGroupedToSpecific(productDetail)
.friendlyName();
return `${friendlyProductName}`;
Expand Down
6 changes: 3 additions & 3 deletions client/components/mma/holiday/Holiday.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { HolidayStopsContainer } from './HolidayStopsContainer';
const productTypeWithHolidayStops = {
...PRODUCT_TYPES.guardianweekly,
holidayStops: {
issueKeyword: '',
issueKeyword: 'issue',
},
};

Expand All @@ -31,7 +31,7 @@ export default {
},
} as Meta<typeof HolidayStopsContainer>;

export const Manage: StoryObj<typeof HolidaysOverview> = {
export const ManageGuardianWeekly: StoryObj<typeof HolidaysOverview> = {
render: () => {
return <HolidaysOverview />;
},
Expand All @@ -52,7 +52,7 @@ export const Manage: StoryObj<typeof HolidaysOverview> = {
},
};

export const Create: StoryObj<typeof HolidayDateChooser> = {
export const CreateGuardianWeekly: StoryObj<typeof HolidayDateChooser> = {
render: () => {
return <HolidayDateChooser />;
},
Expand Down
73 changes: 73 additions & 0 deletions client/components/mma/holiday/HolidayT3.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import type { Meta, StoryObj } from '@storybook/react';
import { rest } from 'msw';
import { ReactRouterDecorator } from '@/.storybook/ReactRouterDecorator';
import { PRODUCT_TYPES } from '@/shared/productTypes';
import { existingHolidays } from '../../../fixtures/holidays';
import { toMembersDataApiResponse } from '../../../fixtures/mdapiResponse';
import {
guardianWeeklyPaidByCard,
tierThree,
} from '../../../fixtures/productBuilder/testProducts';
import { HolidayDateChooser } from './HolidayDateChooser';
import { HolidaysOverview } from './HolidaysOverview';
import { HolidayStopsContainer } from './HolidayStopsContainer';

const productTypeWithHolidayStops = {
...PRODUCT_TYPES.tierthree,
holidayStops: {
issueKeyword: 'issue',
},
};

export default {
component: HolidayStopsContainer,
title: 'Pages/HolidayStops',
decorators: [ReactRouterDecorator],
parameters: {
reactRouter: {
container: (
<HolidayStopsContainer
productType={productTypeWithHolidayStops}
/>
),
},
},
} as Meta<typeof HolidayStopsContainer>;

export const ManageTierThree: StoryObj<typeof HolidaysOverview> = {
render: () => {
return <HolidaysOverview />;
},

parameters: {
msw: [
rest.get('/api/me/mma', (_req, res, ctx) => {
return res(ctx.json(toMembersDataApiResponse(tierThree())));
}),
rest.get('/api/holidays/*', (_req, res, ctx) => {
return res(ctx.json(existingHolidays));
}),
],
},
};

export const CreateTierThree: StoryObj<typeof HolidayDateChooser> = {
render: () => {
return <HolidayDateChooser />;
},

parameters: {
msw: [
rest.get('/api/me/mma', (_req, res, ctx) => {
return res(
ctx.json(
toMembersDataApiResponse(guardianWeeklyPaidByCard()),
),
);
}),
rest.get('/api/holidays/*', (_req, res, ctx) => {
return res(ctx.json(existingHolidays));
}),
],
},
};
16 changes: 14 additions & 2 deletions client/components/mma/shared/benefits/BenefitsConfiguration.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { ProductTypeKeys } from '../../../../../shared/productTypes';
import type { ProductTypeKeys } from '@/shared/productTypes';

/* Product Switch Benefits */
/* Product Switch Benefits, these are also shown on product cards */

const supporterNewsletter = {
name: 'A regular supporter newsletter.',
Expand All @@ -22,6 +22,11 @@ const adFree = {
description: 'Avoid ads on all your devices',
};

const guardianWeekly = {
name: 'Guardian Weekly',
description: 'Print magazine delivered to your door every week',
};

export interface ProductBenefit {
name?: string;
description?: string;
Expand All @@ -42,6 +47,13 @@ export const benefitsConfiguration: {
},
],
supporterplus: [supporterNewsletter, uninterruptedReading, newsApp, adFree],
tierthree: [
guardianWeekly,
supporterNewsletter,
uninterruptedReading,
newsApp,
adFree,
],
membership: [newsApp, uninterruptedReading, supporterNewsletter],
digipack: [],
digitalvoucher: [],
Expand Down
77 changes: 77 additions & 0 deletions client/fixtures/productBuilder/baseProducts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -500,3 +500,80 @@ export function baseSupporterPlus(): ProductDetail {
},
};
}

export function baseTierThree(): ProductDetail {
return {
mmaCategory: 'recurringSupport',
tier: 'Tier Three',
isPaidTier: true,
selfServiceCancellation: {
isAllowed: true,
shouldDisplayEmail: true,
phoneRegionsToDisplay: ['UK & ROW', 'US', 'AUS'],
},
billingCountry: 'United Kingdom',
joinDate: '2024-06-13',
optIn: true,
subscription: {
paymentMethod: 'Card',
card: {
last4: '4242',
expiry: { month: 2, year: 2029 },
type: 'Visa',
stripePublicKeyForUpdate: 'pk_test_Qm3CGRdrV4WfGYCpm0sftR0f',
email: 'rupert.bates+t3@observer.co.uk',
},
contactId: '003UD00000BDAMbYAP',
deliveryAddress: {
addressLine1: 'Kings Place',
addressLine2: '',
town: 'London',
postcode: 'N19GU',
country: 'United Kingdom',
},
safeToUpdatePaymentMethod: true,
start: '2024-06-28',
end: '2025-06-13',
nextPaymentPrice: 2500,
nextPaymentDate: '2024-06-28',
lastPaymentDate: null,
potentialCancellationDate: null,
chargedThroughDate: null,
renewalDate: '2025-06-13',
anniversaryDate: '2025-06-28',
cancelledAt: false,
subscriptionId: 'A-S00897035',
trialLength: 4,
autoRenew: true,
plan: {
name: 'Tier Three',
price: 2500,
currency: '£',
currencyISO: 'GBP',
billingPeriod: 'month',
start: '',
end: '',
shouldBeVisible: false,
features: '',
},
currentPlans: [],
futurePlans: [
{
name: null,
start: '2024-06-28',
end: '2025-06-13',
shouldBeVisible: true,
chargedThrough: null,
price: 2500,
currency: '£',
currencyISO: 'GBP',
billingPeriod: 'month',
features: '',
},
],
readerType: 'Direct',
accountId: '8ad08f069010dd31019011e437574822',
},
isTestUser: false,
};
}
7 changes: 7 additions & 0 deletions client/fixtures/productBuilder/testProducts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
baseMembership,
baseNationalDelivery,
baseSupporterPlus,
baseTierThree,
} from './baseProducts';
import { cards, ProductBuilder } from './productBuilder';

Expand Down Expand Up @@ -242,6 +243,12 @@ export function supporterPlusInOfferPeriod() {
.getProductDetailObject();
}

export function tierThree() {
return new ProductBuilder(baseTierThree())
.payByCard()
.getProductDetailObject();
}

export function patronDigitalPack() {
return new ProductBuilder(baseDigitalPack())
.payByCard()
Expand Down
35 changes: 35 additions & 0 deletions cypress/tests/mocked/parallel-3/holidayStops.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,41 @@ describe('Holiday stops', () => {
cy.get('@create_holiday_stop.all').should('have.length', 1);
});

it('can add a new holiday stop for Tier Three', () => {
cy.visit('/suspend/digital+print');
cy.wait('@fetch_existing_holidays');
cy.wait('@product_detail');
cy.get('[data-cy="create-suspension-cta"] button').click();

cy.findByText('Choose the dates you will be away');

// Selects 09/02/2022 - 11/02/2022
cy.get('[data-cy="date-picker"] div').eq(9).click();
cy.get('[data-cy="date-picker"] div').eq(11).click();
cy.wait('@fetch_potential_holidays');

// Total issues suspended
cy.get('[data-cy="suspension-issue-count"]').eq(0).contains('1 issue');

cy.findByText('Review details').click();

cy.get('table').contains('9 February - 11 February 2022');
cy.get('table').contains('1 issue');
cy.get('table').contains('£2.89 off your 1 February 2023 payment');

cy.findByText('Confirm').click();

cy.wait('@create_holiday_stop');
cy.findByText('Your schedule has been set').should('exist');

cy.findByText('Schedule another suspension').click();
cy.wait('@fetch_existing_holidays');
cy.wait('@product_detail');

cy.get('@fetch_existing_holidays.all').should('have.length', 2);
cy.get('@create_holiday_stop.all').should('have.length', 1);
});

it('can not create a holiday stop for date range when there are no deliveries', () => {
cy.intercept('GET', '/api/holidays/*/potential?*', {
statusCode: 200,
Expand Down
1 change: 1 addition & 0 deletions docs/07-testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ The mocked tests use the following commands in `package.json`:
- `yarn cypress:mocked:server`: starts a dev server (essentially the same as the standard `yarn watch` command but with the `CYPRESS` variable set to `'SKIP_IDAPI'`, and doesn't open a new browser tab).
- `yarn cypress:mocked:open`: opens the Cypress test runner in mocked mode.
- `yarn cypress:mocked:run`: runs the Cypress tests headless in mocked mode.
- `yarn cypress:mocked:runOnly [file to run]`: runs one Cypress test file eg. `yarn cypress:mocked:runOnly cypress/tests/mocked/parallel-3/holidayStops.cy.ts`

In CI, the mocked tests are run by the `cypress-mocked.yml` GitHub Actions job.

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"build-storybook": "storybook build -s '.storybook/static'",
"cypress:mocked:open": "DEBUG=cypress:* cypress open --config '{\"e2e\":{\"specPattern\":\"cypress/tests/mocked/**/*.cy.{js,jsx,ts,tsx}\"}}' --e2e --browser chrome",
"cypress:mocked:run": "cypress run --config '{\"e2e\":{\"specPattern\":\"cypress/tests/mocked/**/*.cy.{js,jsx,ts,tsx}\"}}' --e2e --browser chrome",
"cypress:mocked:runOnly": "cypress run --e2e --browser chrome --spec ",
"cypress:mocked:server": "yarn bundle-dev-server && (yarn bundle-dev-server-cypress -w & yarn start & yarn serve-dev-cypress)",
"cypress:e2e:open": "cypress open --config '{\"e2e\":{\"specPattern\":\"cypress/tests/e2e/**/*.cy.{js,jsx,ts,tsx}\"}}' --e2e --browser chrome",
"cypress:e2e:run": "cypress run --config '{\"e2e\":{\"specPattern\":\"cypress/tests/e2e/**/*.cy.{js,jsx,ts,tsx}\"}}' --e2e --browser chrome",
Expand Down
Loading

0 comments on commit 16341c0

Please sign in to comment.