This commit is contained in:
Davey Alvarez 2024-09-23 17:09:14 -07:00
Родитель 3da291f829
Коммит d0f7bcd26c
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: A538D290868DCC59
4 изменённых файлов: 104 добавлений и 4 удалений

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

@ -23,11 +23,18 @@ import { MockStatsDProvider } from '@fxa/shared/metrics/statsd';
import { PriceManager } from '@fxa/payments/customer'; import { PriceManager } from '@fxa/payments/customer';
import { MockFirestoreProvider } from '@fxa/shared/db/firestore'; import { MockFirestoreProvider } from '@fxa/shared/db/firestore';
import { MockPaymentsGleanFactory } from './glean.provider'; import { MockPaymentsGleanFactory } from './glean.provider';
import {
AccountFactory,
MockAccountDatabaseNestFactory,
} from '@fxa/shared/db/mysql/account';
import { AccountManager } from '@fxa/shared/account/account';
import { faker } from '@faker-js/faker';
describe('PaymentsGleanService', () => { describe('PaymentsGleanService', () => {
let paymentsGleanService: PaymentsGleanService; let paymentsGleanService: PaymentsGleanService;
let paymentsGleanManager: PaymentsGleanManager; let paymentsGleanManager: PaymentsGleanManager;
let productConfigurationManager: ProductConfigurationManager; let productConfigurationManager: ProductConfigurationManager;
let accountsManager: AccountManager;
beforeEach(async () => { beforeEach(async () => {
const moduleRef = await Test.createTestingModule({ const moduleRef = await Test.createTestingModule({
@ -35,6 +42,7 @@ describe('PaymentsGleanService', () => {
MockPaymentsGleanFactory, MockPaymentsGleanFactory,
MockStrapiClientConfigProvider, MockStrapiClientConfigProvider,
MockStripeConfigProvider, MockStripeConfigProvider,
MockAccountDatabaseNestFactory,
MockFirestoreProvider, MockFirestoreProvider,
MockStatsDProvider, MockStatsDProvider,
StrapiClient, StrapiClient,
@ -43,18 +51,21 @@ describe('PaymentsGleanService', () => {
PaymentsGleanManager, PaymentsGleanManager,
ProductConfigurationManager, ProductConfigurationManager,
PaymentsGleanService, PaymentsGleanService,
AccountManager,
], ],
}).compile(); }).compile();
paymentsGleanService = moduleRef.get(PaymentsGleanService); paymentsGleanService = moduleRef.get(PaymentsGleanService);
paymentsGleanManager = moduleRef.get(PaymentsGleanManager); paymentsGleanManager = moduleRef.get(PaymentsGleanManager);
productConfigurationManager = moduleRef.get(ProductConfigurationManager); productConfigurationManager = moduleRef.get(ProductConfigurationManager);
accountsManager = moduleRef.get(AccountManager);
}); });
it('should be defined', () => { it('should be defined', () => {
expect(paymentsGleanService).toBeDefined(); expect(paymentsGleanService).toBeDefined();
expect(paymentsGleanManager).toBeDefined(); expect(paymentsGleanManager).toBeDefined();
expect(productConfigurationManager).toBeDefined(); expect(productConfigurationManager).toBeDefined();
expect(accountsManager).toBeDefined();
}); });
describe('handleEventFxaPaySetupView', () => { describe('handleEventFxaPaySetupView', () => {
@ -106,5 +117,27 @@ describe('PaymentsGleanService', () => {
{ priceId: '', productId: '' } { priceId: '', productId: '' }
); );
}); });
it('should not call recordFxaPaySetupView if opted out', async () => {
const uid = Buffer.from(
faker.string.hexadecimal({
length: 32,
prefix: '',
casing: 'lower',
}),
'hex'
);
const mockUser = AccountFactory({
uid,
metricsOptOutAt: new Date().valueOf(),
});
jest.spyOn(accountsManager, 'getAccounts').mockResolvedValue([mockUser]);
await paymentsGleanService.handleEventFxaPaySetupView({
...mockMetricsData,
uid: uid.toString('hex'),
});
expect(paymentsGleanManager.recordFxaPaySetupView).not.toHaveBeenCalled();
});
}); });
}); });

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

@ -7,6 +7,7 @@ import { ProductConfigurationManager } from '@fxa/shared/cms';
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { mapParams } from './utils/mapParams'; import { mapParams } from './utils/mapParams';
import { PaymentsGleanManager } from './glean.manager'; import { PaymentsGleanManager } from './glean.manager';
import { AccountManager } from '@fxa/shared/account/account';
import { SubplatInterval } from '@fxa/payments/customer'; import { SubplatInterval } from '@fxa/payments/customer';
@Injectable() @Injectable()
@ -15,7 +16,8 @@ export class PaymentsGleanService {
constructor( constructor(
private productConfigurationManager: ProductConfigurationManager, private productConfigurationManager: ProductConfigurationManager,
private paymentsGleanManager: PaymentsGleanManager private paymentsGleanManager: PaymentsGleanManager,
private accountManager: AccountManager
) { ) {
this.emitter = new Emittery<GleanEvents>(); this.emitter = new Emittery<GleanEvents>();
this.emitter.on( this.emitter.on(
@ -30,9 +32,17 @@ export class PaymentsGleanService {
async handleEventFxaPaySetupView(metricsData: FxaPaySetupViewMetrics) { async handleEventFxaPaySetupView(metricsData: FxaPaySetupViewMetrics) {
const { offeringId, interval } = mapParams(metricsData.params); const { offeringId, interval } = mapParams(metricsData.params);
const cmsData = await this.retrieveCMSData(offeringId, interval); const [cmsData, optedOut] = await Promise.all([
this.retrieveCMSData(offeringId, interval),
this.retrieveOptOut(metricsData.uid),
]);
await this.paymentsGleanManager.recordFxaPaySetupView(metricsData, cmsData); if (!optedOut) {
await this.paymentsGleanManager.recordFxaPaySetupView(
metricsData,
cmsData
);
}
} }
private async retrieveCMSData(offeringId: string, interval: SubplatInterval) { private async retrieveCMSData(offeringId: string, interval: SubplatInterval) {
@ -53,4 +63,10 @@ export class PaymentsGleanService {
}; };
} }
} }
private async retrieveOptOut(uid?: string): Promise<boolean> {
if (!uid) return false;
const accounts = await this.accountManager.getAccounts([uid]);
return accounts[0].metricsOptOutAt !== null;
}
} }

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

@ -6,6 +6,7 @@ export * from './lib/associated-types';
export * from './lib/kysely-types'; export * from './lib/kysely-types';
export { export {
CartFactory, CartFactory,
AccountFactory,
AccountCustomerFactory, AccountCustomerFactory,
PaypalCustomerFactory, PaypalCustomerFactory,
} from './lib/factories'; } from './lib/factories';

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

@ -4,7 +4,12 @@
import { faker } from '@faker-js/faker'; import { faker } from '@faker-js/faker';
import { AccountCustomer, NewCart, PaypalCustomer } from './associated-types'; import {
Account,
AccountCustomer,
NewCart,
PaypalCustomer,
} from './associated-types';
import { CartEligibilityStatus, CartState } from './kysely-types'; import { CartEligibilityStatus, CartState } from './kysely-types';
export const CartFactory = (override?: Partial<NewCart>): NewCart => ({ export const CartFactory = (override?: Partial<NewCart>): NewCart => ({
@ -39,6 +44,51 @@ export const CartFactory = (override?: Partial<NewCart>): NewCart => ({
...override, ...override,
}); });
const getHexBuffer = (length: number, prefix = ''): Buffer => {
return Buffer.from(
faker.string.hexadecimal({
length,
prefix,
casing: 'lower',
}),
'hex'
);
};
export const AccountFactory = (override?: Partial<Account>): Account => ({
uid: getHexBuffer(32),
createdAt: faker.date.recent().getTime(),
email: faker.internet.email(),
normalizedEmail: faker.internet.email().toLocaleLowerCase(),
emailCode: getHexBuffer(16),
emailVerified: 1,
verifierVersion: 1,
kA: getHexBuffer(32),
wrapWrapKb: Buffer.from(
faker.string.hexadecimal({
length: 32,
prefix: '',
casing: 'lower',
}),
'hex'
),
wrapWrapKbVersion2: getHexBuffer(32),
authSalt: getHexBuffer(32),
verifyHash: getHexBuffer(32),
verifierSetAt: faker.date.recent().getTime(),
verifyHashVersion2: getHexBuffer(32),
locale: 'en-US',
lockedAt: null,
profileChangedAt: null,
keysChangedAt: null,
ecosystemAnonId: faker.string.numeric(),
disabledAt: null,
metricsOptOutAt: null,
clientSalt: null,
atLeast18AtReg: 1,
...override,
});
export const AccountCustomerFactory = ( export const AccountCustomerFactory = (
override?: Partial<AccountCustomer> override?: Partial<AccountCustomer>
): AccountCustomer => ({ ): AccountCustomer => ({