chore(factories): move factories into their respective shared-contentful directories

Because:

* The main factories file was getting a bit out of hand and separating them keeps everything more organized.

This commit:

* Moves eligibility and services factories into their own directories.
* Updates factories that include more than the single override parameter.
* Updates paths where applicable.
* Updates tests where applicable.
* Adds missing tests for planIdsToClientCapabilities

Closes FXA-8621
This commit is contained in:
Meghan Sardesai 2023-11-04 17:48:04 -04:00
Родитель 1b1bda3ffc
Коммит a54331a42f
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 9A46BEBC2E8A3934
11 изменённых файлов: 357 добавлений и 225 удалений

Просмотреть файл

@ -5,38 +5,45 @@ import { Test, TestingModule } from '@nestjs/testing';
import {
ContentfulManager,
CapabilityCapabilitiesResultFactory,
CapabilityOfferingResultFactory,
CapabilitiesResultFactory,
CapabilityServiceByPlanIdsResultUtil,
CapabilityServicesResultFactory,
ServiceResultFactory,
ServicesWithCapabilitiesResultUtil,
} from '@fxa/shared/contentful';
import { CapabilityManager } from './capability.manager';
describe('CapabilityManager', () => {
let manager: CapabilityManager;
let mockContentfulManager: ContentfulManager;
let mockResult: ServicesWithCapabilitiesResultUtil;
beforeEach(async () => {
mockResult = {} as any;
mockContentfulManager = {
getServicesWithCapabilities: jest.fn().mockResolvedValueOnce(mockResult),
} as any;
const module: TestingModule = await Test.createTestingModule({
providers: [
{ provide: ContentfulManager, useValue: mockContentfulManager },
CapabilityManager,
],
}).compile();
manager = module.get<CapabilityManager>(CapabilityManager);
});
it('should be defined', async () => {
expect(manager).toBeDefined();
expect(manager).toBeInstanceOf(CapabilityManager);
});
describe('getClients', () => {
let manager: CapabilityManager;
let mockContentfulManager: ContentfulManager;
let mockResult: ServicesWithCapabilitiesResultUtil;
beforeEach(async () => {
mockResult = {} as ServicesWithCapabilitiesResultUtil;
mockContentfulManager = {
getServicesWithCapabilities: jest
.fn()
.mockResolvedValueOnce(mockResult),
} as any;
const module: TestingModule = await Test.createTestingModule({
providers: [
{ provide: ContentfulManager, useValue: mockContentfulManager },
CapabilityManager,
],
}).compile();
manager = module.get<CapabilityManager>(CapabilityManager);
});
it('should be defined', async () => {
expect(manager).toBeDefined();
expect(manager).toBeInstanceOf(CapabilityManager);
});
it('should return empty results', async () => {
mockResult.getServices = jest.fn().mockReturnValueOnce(undefined);
const result = await manager.getClients();
@ -44,34 +51,118 @@ describe('CapabilityManager', () => {
});
it('should return services with capabilities', async () => {
const clientResults = ServiceResultFactory({
oauthClientId: 'client1',
capabilitiesCollection: {
items: [
{ slug: 'exampleCap0' },
{ slug: 'exampleCap2' },
{ slug: 'exampleCap4' },
{ slug: 'exampleCap5' },
{ slug: 'exampleCap6' },
{ slug: 'exampleCap8' },
],
},
});
const clientResults = [
ServiceResultFactory({
oauthClientId: 'client1',
capabilitiesCollection: {
items: [
CapabilitiesResultFactory({ slug: 'exampleCap0' }),
CapabilitiesResultFactory({ slug: 'exampleCap2' }),
CapabilitiesResultFactory({ slug: 'exampleCap4' }),
CapabilitiesResultFactory({ slug: 'exampleCap5' }),
CapabilitiesResultFactory({ slug: 'exampleCap6' }),
CapabilitiesResultFactory({ slug: 'exampleCap8' }),
],
},
}),
];
mockResult.getServices = jest.fn().mockReturnValue(clientResults);
const result = await manager.getClients();
expect(result.length).toBe(1);
expect(result[0].clientId).toBe('client1');
const actualCapabilities = [
'exampleCap0',
'exampleCap2',
'exampleCap4',
'exampleCap5',
'exampleCap6',
'exampleCap8',
];
const actualCapabilities =
clientResults[0].capabilitiesCollection.items.map(
(capability) => capability.slug
);
expect(result[0].capabilities).toHaveLength(6);
expect(result[0].capabilities).toStrictEqual(actualCapabilities);
});
});
describe('planIdsToClientCapabilities', () => {
let manager: CapabilityManager;
let mockContentfulManager: ContentfulManager;
let mockResult: CapabilityServiceByPlanIdsResultUtil;
beforeEach(async () => {
mockResult = {} as CapabilityServiceByPlanIdsResultUtil;
mockContentfulManager = {
getPurchaseDetailsForCapabilityServiceByPlanIds: jest
.fn()
.mockResolvedValueOnce(mockResult),
} as any;
const module: TestingModule = await Test.createTestingModule({
providers: [
{ provide: ContentfulManager, useValue: mockContentfulManager },
CapabilityManager,
],
}).compile();
manager = module.get<CapabilityManager>(CapabilityManager);
});
it('should be defined', async () => {
expect(manager).toBeDefined();
expect(manager).toBeInstanceOf(CapabilityManager);
});
it('should return empty results', async () => {
mockResult.capabilityOfferingForPlanId = jest
.fn()
.mockReturnValueOnce(undefined);
const result = await manager.planIdsToClientCapabilities(['planId1']);
expect(Object.keys(result).length).toBe(0);
});
it('should return planIds to client capabilities', async () => {
const offeringResult = CapabilityOfferingResultFactory({
capabilitiesCollection: {
items: [
CapabilityCapabilitiesResultFactory({
slug: 'slug1',
servicesCollection: {
items: [
CapabilityServicesResultFactory({
oauthClientId: 'clientId1',
}),
],
},
}),
CapabilityCapabilitiesResultFactory({
slug: 'slug2a',
servicesCollection: {
items: [
CapabilityServicesResultFactory({
oauthClientId: 'clientId2',
}),
],
},
}),
CapabilityCapabilitiesResultFactory({
slug: 'slug2b',
servicesCollection: {
items: [
CapabilityServicesResultFactory({
oauthClientId: 'clientId2',
}),
],
},
}),
],
},
});
mockResult.capabilityOfferingForPlanId = jest
.fn()
.mockReturnValueOnce(offeringResult);
const result = await manager.planIdsToClientCapabilities(['planId1']);
expect(Object.keys(result).length).toBe(2);
expect(result).toStrictEqual({
clientId1: ['slug1'],
clientId2: ['slug2a', 'slug2b'],
});
});
});
});

Просмотреть файл

@ -38,6 +38,8 @@ export class CapabilityManager {
async planIdsToClientCapabilities(
subscribedPrices: string[]
): Promise<Record<string, string[]>> {
if (!subscribedPrices.length) return {};
const purchaseDetails =
await this.contentfulManager.getPurchaseDetailsForCapabilityServiceByPlanIds(
[...subscribedPrices]

Просмотреть файл

@ -7,8 +7,9 @@ import {
ContentfulManager,
EligibilityContentByPlanIdsResultUtil,
EligibilityOfferingResultFactory,
EligibilitySubgroupOfferingResultFactory,
EligibilitySubgroupResultFactory,
} from '../../../../shared/contentful/src';
} from '@fxa/shared/contentful';
import { EligibilityManager } from './eligibility.manager';
import { OfferingComparison } from './eligibility.types';
@ -18,7 +19,7 @@ describe('EligibilityManager', () => {
let mockResult: EligibilityContentByPlanIdsResultUtil;
beforeEach(async () => {
mockResult = {} as any;
mockResult = {} as EligibilityContentByPlanIdsResultUtil;
mockContentfulManager = {
getPurchaseDetailsForEligibility: jest
.fn()
@ -59,14 +60,29 @@ describe('EligibilityManager', () => {
});
it('should return subgroup upgrade target offeringStripeProductIds as upgrade comparison', async () => {
const offeringResult = EligibilityOfferingResultFactory(
{ stripeProductId: 'prod_test2' },
[],
[
{ stripeProductId: 'prod_test', countries: ['usa'] },
{ stripeProductId: 'prod_test2', countries: ['usa'] },
]
);
const offeringResult = EligibilityOfferingResultFactory({
stripeProductId: 'prod_test2',
linkedFrom: {
subGroupCollection: {
items: [
EligibilitySubgroupResultFactory({
offeringCollection: {
items: [
EligibilitySubgroupOfferingResultFactory({
stripeProductId: 'prod_test',
countries: ['usa'],
}),
EligibilitySubgroupOfferingResultFactory({
stripeProductId: 'prod_test2',
countries: ['usa'],
}),
],
},
}),
],
},
},
});
mockResult.offeringForPlanId = jest
.fn()
.mockReturnValueOnce(offeringResult);
@ -80,14 +96,29 @@ describe('EligibilityManager', () => {
});
it('should return subgroup downgrade target offeringStripeProductIds as downgrade comparison', async () => {
const offeringResult = EligibilityOfferingResultFactory(
{ stripeProductId: 'prod_test' },
[],
[
{ stripeProductId: 'prod_test', countries: ['usa'] },
{ stripeProductId: 'prod_test2', countries: ['usa'] },
]
);
const offeringResult = EligibilityOfferingResultFactory({
stripeProductId: 'prod_test',
linkedFrom: {
subGroupCollection: {
items: [
EligibilitySubgroupResultFactory({
offeringCollection: {
items: [
EligibilitySubgroupOfferingResultFactory({
stripeProductId: 'prod_test',
countries: ['usa'],
}),
EligibilitySubgroupOfferingResultFactory({
stripeProductId: 'prod_test2',
countries: ['usa'],
}),
],
},
}),
],
},
},
});
mockResult.offeringForPlanId = jest
.fn()
.mockReturnValueOnce(offeringResult);
@ -121,16 +152,29 @@ describe('EligibilityManager', () => {
});
it('should return upgrade comparison for upgrade planId', async () => {
const offeringResult = EligibilityOfferingResultFactory(
{
stripeProductId: 'prod_test2',
const offeringResult = EligibilityOfferingResultFactory({
stripeProductId: 'prod_test2',
linkedFrom: {
subGroupCollection: {
items: [
EligibilitySubgroupResultFactory({
offeringCollection: {
items: [
EligibilitySubgroupOfferingResultFactory({
stripeProductId: 'prod_test',
countries: ['usa'],
}),
EligibilitySubgroupOfferingResultFactory({
stripeProductId: 'prod_test2',
countries: ['usa'],
}),
],
},
}),
],
},
},
[],
[
{ stripeProductId: 'prod_test', countries: ['usa'] },
{ stripeProductId: 'prod_test2', countries: ['usa'] },
]
);
});
const existingResult = EligibilityOfferingResultFactory({
stripeProductId: 'prod_test',
});
@ -148,20 +192,47 @@ describe('EligibilityManager', () => {
});
it('should return multiple comparisons in multiple subgroups', async () => {
const offeringResult = EligibilityOfferingResultFactory(
{ stripeProductId: 'prod_test2' },
[
EligibilitySubgroupResultFactory({}, [
{ stripeProductId: 'prod_test', countries: ['usa'] },
{ stripeProductId: 'prod_test2', countries: ['usa'] },
{ stripeProductId: 'prod_test3', countries: ['usa'] },
]),
],
[
{ stripeProductId: 'prod_test', countries: ['usa'] },
{ stripeProductId: 'prod_test2', countries: ['usa'] },
]
);
const offeringResult = EligibilityOfferingResultFactory({
stripeProductId: 'prod_test2',
linkedFrom: {
subGroupCollection: {
items: [
EligibilitySubgroupResultFactory({
offeringCollection: {
items: [
EligibilitySubgroupOfferingResultFactory({
stripeProductId: 'prod_test',
countries: ['usa'],
}),
EligibilitySubgroupOfferingResultFactory({
stripeProductId: 'prod_test2',
countries: ['usa'],
}),
EligibilitySubgroupOfferingResultFactory({
stripeProductId: 'prod_test3',
countries: ['usa'],
}),
],
},
}),
EligibilitySubgroupResultFactory({
offeringCollection: {
items: [
EligibilitySubgroupOfferingResultFactory({
stripeProductId: 'prod_test',
countries: ['usa'],
}),
EligibilitySubgroupOfferingResultFactory({
stripeProductId: 'prod_test2',
countries: ['usa'],
}),
],
},
}),
],
},
},
});
const existingResult = EligibilityOfferingResultFactory({
stripeProductId: 'prod_test',
});

Просмотреть файл

@ -7,10 +7,8 @@ import { ContentfulClient } from './contentful.client';
import { ContentfulManager } from './contentful.manager';
import {
EligibilityContentByPlanIdsQueryFactory,
ServicesWithCapabilitiesQueryFactory,
} from './factories';
import {
EligibilityContentByPlanIdsResultUtil,
ServicesWithCapabilitiesQueryFactory,
ServicesWithCapabilitiesResultUtil,
} from '../../src';
import { PurchaseWithDetailsOfferingContentUtil } from './queries/purchase-with-details-offering-content';

Просмотреть файл

@ -7,107 +7,11 @@ import { faker } from '@faker-js/faker';
import { TypedDocumentNode } from '@graphql-typed-document-node/core';
import {
EligibilityContentByPlanIdsQuery,
OfferingQuery,
PurchaseWithDetailsQuery,
ServicesWithCapabilitiesQuery,
} from '../__generated__/graphql';
import {
EligibilityOfferingResult,
EligibilitySubgroupOfferingResult,
EligibilitySubgroupResult,
} from './queries/eligibility-content-by-plan-ids';
import {
CapabilitiesResult,
ServiceResult,
} from './queries/services-with-capabilities';
import { ContentfulErrorResponse } from './types';
export const EligibilityContentByPlanIdsQueryFactory = (
override?: Partial<EligibilityContentByPlanIdsQuery>
): EligibilityContentByPlanIdsQuery => {
const stripeProductId = faker.string.sample();
return {
purchaseCollection: {
items: [
{
stripePlanChoices: [faker.string.sample()],
offering: {
stripeProductId,
countries: [faker.string.sample()],
linkedFrom: {
subGroupCollection: {
items: [
{
groupName: faker.string.sample(),
offeringCollection: {
items: [
{
stripeProductId,
countries: [faker.string.sample()],
},
],
},
},
],
},
},
},
},
],
},
...override,
};
};
export const EligibilityOfferingResultFactory = (
override?: Partial<EligibilityOfferingResult>,
subGroupCollectionExtension?: EligibilitySubgroupResult[],
subGroupOfferingCollectionExtension?: EligibilitySubgroupOfferingResult[]
): EligibilityOfferingResult => ({
stripeProductId: faker.string.sample(),
countries: [faker.string.sample()],
linkedFrom: {
subGroupCollection: {
items: [
{
groupName: faker.string.sample(),
offeringCollection: {
items: [
{
stripeProductId: faker.string.sample(),
countries: [faker.string.sample()],
},
...(subGroupOfferingCollectionExtension ?? []),
],
},
},
...(subGroupCollectionExtension ?? []),
],
},
},
...override,
});
export const EligibilitySubgroupResultFactory = (
override?: Partial<EligibilitySubgroupResult>,
offeringCollection?: EligibilitySubgroupOfferingResult[]
): EligibilitySubgroupResult => ({
groupName: faker.string.sample(),
offeringCollection: {
items: [...(offeringCollection ?? [])],
},
...override,
});
export const EligibilitySubgroupOfferingResultFactory = (
override?: Partial<EligibilitySubgroupOfferingResult>
): EligibilitySubgroupOfferingResult => ({
stripeProductId: faker.string.sample(),
countries: [faker.string.sample()],
...override,
});
export const OfferingQueryFactory = (
override?: Partial<OfferingQuery>
): OfferingQuery => ({
@ -141,39 +45,6 @@ export const PurchaseWithDetailsQueryFactory = (
...override,
});
export const ServicesWithCapabilitiesQueryFactory = (
override?: Partial<ServicesWithCapabilitiesQuery>
): ServicesWithCapabilitiesQuery => ({
serviceCollection: {
items: [
{
oauthClientId: faker.string.sample(),
capabilitiesCollection: {
items: [
{
slug: faker.string.sample(),
},
],
},
},
],
},
...override,
});
export const ServiceResultFactory = (
override?: Partial<ServiceResult>,
capabilitiesCollection?: CapabilitiesResult[]
): ServiceResult[] => [
{
oauthClientId: faker.string.sample(),
capabilitiesCollection: {
items: [...(capabilitiesCollection ?? [])],
},
...override,
},
];
/**
* Generates a graphql response from the contentful client based on the passed query.
* Use one of the query factories to provide data for the factory result.

Просмотреть файл

@ -0,0 +1,59 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
import { faker } from '@faker-js/faker';
import { EligibilityContentByPlanIdsQuery } from '../../../__generated__/graphql';
import {
EligibilityOfferingResult,
EligibilitySubgroupOfferingResult,
EligibilitySubgroupResult,
} from '.';
export const EligibilityContentByPlanIdsQueryFactory = (
override?: Partial<EligibilityContentByPlanIdsQuery>
): EligibilityContentByPlanIdsQuery => {
return {
purchaseCollection: {
items: [
{
stripePlanChoices: [faker.string.sample()],
offering: EligibilityOfferingResultFactory(),
},
],
},
...override,
};
};
export const EligibilityOfferingResultFactory = (
override?: Partial<EligibilityOfferingResult>
): EligibilityOfferingResult => ({
stripeProductId: faker.string.sample(),
countries: [faker.string.sample()],
linkedFrom: {
subGroupCollection: {
items: [EligibilitySubgroupResultFactory()],
},
},
...override,
});
export const EligibilitySubgroupResultFactory = (
override?: Partial<EligibilitySubgroupResult>
): EligibilitySubgroupResult => ({
groupName: faker.string.sample(),
offeringCollection: {
items: [EligibilitySubgroupOfferingResultFactory()],
},
...override,
});
export const EligibilitySubgroupOfferingResultFactory = (
override?: Partial<EligibilitySubgroupOfferingResult>
): EligibilitySubgroupOfferingResult => ({
stripeProductId: faker.string.sample(),
countries: [faker.string.sample()],
...override,
});

Просмотреть файл

@ -2,6 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
export * from './factories';
export * from './query';
export * from './types';
export * from './util';

Просмотреть файл

@ -2,9 +2,11 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
import { EligibilityContentByPlanIdsQueryFactory } from '../../factories';
import { EligibilityContentByPlanIdsResult } from './types';
import { EligibilityContentByPlanIdsResultUtil } from './util';
import {
EligibilityContentByPlanIdsQueryFactory,
EligibilityContentByPlanIdsResult,
EligibilityContentByPlanIdsResultUtil,
} from '.';
describe('EligibilityContentByPlanIdsResultUtil', () => {
it('should create a util from response', () => {

Просмотреть файл

@ -0,0 +1,34 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
import { faker } from '@faker-js/faker';
import { ServicesWithCapabilitiesQuery } from '../../../__generated__/graphql';
import { CapabilitiesResult, ServiceResult } from '.';
export const ServicesWithCapabilitiesQueryFactory = (
override?: Partial<ServicesWithCapabilitiesQuery>
): ServicesWithCapabilitiesQuery => ({
serviceCollection: {
items: [ServiceResultFactory()],
},
...override,
});
export const ServiceResultFactory = (
override?: Partial<ServiceResult>
): ServiceResult => ({
oauthClientId: faker.string.sample(),
capabilitiesCollection: {
items: [CapabilitiesResultFactory()],
},
...override,
});
export const CapabilitiesResultFactory = (
override?: Partial<CapabilitiesResult>
): CapabilitiesResult => ({
slug: faker.string.sample(),
...override,
});

Просмотреть файл

@ -2,6 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
export * from './factories';
export * from './query';
export * from './types';
export * from './util';

Просмотреть файл

@ -2,9 +2,11 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
import { ServicesWithCapabilitiesQueryFactory } from '../../factories';
import { ServicesWithCapabilitiesResult } from './types';
import { ServicesWithCapabilitiesResultUtil } from './util';
import {
ServicesWithCapabilitiesQueryFactory,
ServicesWithCapabilitiesResult,
ServicesWithCapabilitiesResultUtil,
} from '.';
describe('ServicesWithCapabilitiesResultUtil', () => {
it('should create a util from response', () => {