Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Add Unit Tests #25

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import { DonationPaymentInfo } from '@internetarchive/donation-form-data-models';
import { ApplePaySessionDataSourceDelegate } from './apple-pay-session-datasource-delegate';

export interface ApplePaySessionDataSourceInterface {
delegate?: ApplePaySessionDataSourceDelegate;
donationInfo: DonationPaymentInfo;
onvalidatemerchant(event: ApplePayJS.ApplePayValidateMerchantEvent): Promise<void>;
onpaymentauthorized(event: ApplePayJS.ApplePayPaymentAuthorizedEvent): Promise<void>;
oncancel(): Promise<void>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import { ApplePaySessionDataSourceDelegate } from './apple-pay-session-datasourc

export class ApplePaySessionDataSource implements ApplePaySessionDataSourceInterface {
delegate?: ApplePaySessionDataSourceDelegate;
donationInfo: DonationPaymentInfo;

private donationInfo: DonationPaymentInfo;
private session: ApplePaySession;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private applePayInstance: any;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export class ApplePayFlowHandler
paymentComplete(response: DonationResponse): void {
if (response.success) {
const successResponse = response.value as SuccessResponse;
if (this.applePayDataSource?.donationInfo.donationType == DonationType.OneTime) {
if (successResponse.donationType == DonationType.OneTime) {
this.donationFlowModalManager.showUpsellModal({
oneTimeAmount: successResponse.amount,
yesSelected: this.modalYesSelected.bind(this, successResponse),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { MockApplePayPayment } from './payment-clients/mock-applepay-payment';

export class MockApplePayAuthorizedEvent extends ApplePayJS.ApplePayPaymentAuthorizedEvent {
readonly payment: ApplePayJS.ApplePayPayment = new MockApplePayPayment();
}
87 changes: 87 additions & 0 deletions packages/donation-form/test/mocks/mock-apple-pay-session.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/no-unused-vars */
export class MockApplePaySession implements ApplePaySession {
oncancel: (event: ApplePayJS.Event) => void = () => {
console.log('oncancel');
};
onpaymentauthorized: (event: ApplePayJS.ApplePayPaymentAuthorizedEvent) => void = () => {
console.log('onpaymentauthorized');
};
onpaymentmethodselected: (event: ApplePayJS.ApplePayPaymentMethodSelectedEvent) => void = () => {
console.log('onpaymentmethodselected');
};
onshippingcontactselected: (
event: ApplePayJS.ApplePayShippingContactSelectedEvent,
) => void = () => {
console.log('onshippingcontactselected');
};
onshippingmethodselected: (
event: ApplePayJS.ApplePayShippingMethodSelectedEvent,
) => void = () => {
console.log('onshippingmethodselected');
};
onvalidatemerchant: (event: ApplePayJS.ApplePayValidateMerchantEvent) => void = () => {
console.log('onvalidatemerchant');
};
abort(): void {
throw new Error('Method not implemented.');
}
begin(): void {
throw new Error('Method not implemented.');
}
completeMerchantValidation(merchantSession: any): void {
throw new Error('Method not implemented.');
}
completePayment(result: number | ApplePayJS.ApplePayPaymentAuthorizationResult): void {
throw new Error('Method not implemented.');
}
completePaymentMethodSelection(
newTotal: ApplePayJS.ApplePayLineItem,
newLineItems: ApplePayJS.ApplePayLineItem[],
): void;
completePaymentMethodSelection(update: ApplePayJS.ApplePayPaymentMethodUpdate): void;
completePaymentMethodSelection(newTotal: any, newLineItems?: any): void {
throw new Error('Method not implemented.');
}
completeShippingContactSelection(
status: number,
newShippingMethods: ApplePayJS.ApplePayShippingMethod[],
newTotal: ApplePayJS.ApplePayLineItem,
newLineItems: ApplePayJS.ApplePayLineItem[],
): void;
completeShippingContactSelection(update: ApplePayJS.ApplePayShippingContactUpdate): void;
completeShippingContactSelection(
status: any,
newShippingMethods?: any,
newTotal?: any,
newLineItems?: any,
): void {
throw new Error('Method not implemented.');
}
completeShippingMethodSelection(
status: number,
newTotal: ApplePayJS.ApplePayLineItem,
newLineItems: ApplePayJS.ApplePayLineItem[],
): void;
completeShippingMethodSelection(update: ApplePayJS.ApplePayShippingMethodUpdate): void;
completeShippingMethodSelection(status: any, newTotal?: any, newLineItems?: any): void {
throw new Error('Method not implemented.');
}
addEventListener(
type: string,
listener: EventListener | EventListenerObject | null,
options?: boolean | AddEventListenerOptions,
): void {
throw new Error('Method not implemented.');
}
dispatchEvent(event: Event): boolean {
throw new Error('Method not implemented.');
}
removeEventListener(
type: string,
callback: EventListener | EventListenerObject | null,
options?: boolean | EventListenerOptions,
): void {
throw new Error('Method not implemented.');
}
}
19 changes: 18 additions & 1 deletion packages/donation-form/test/mocks/mock-braintree-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,19 @@ import { MockBraintreeClient } from './payment-clients/mock-braintree-client';
import { PaymentProvidersInterface } from '../../src/braintree-manager/payment-providers-interface';

export class MockBraintreeManager implements BraintreeManagerInterface {
submitDonationOptions?: {
nonce: string;
paymentProvider: PaymentProvider;
donationInfo: DonationPaymentInfo;
billingInfo: BillingInfo;
customerInfo: CustomerInfo;
upsellOnetimeTransactionId?: string | undefined;
customerId?: string | undefined;
recaptchaToken?: string | undefined;
bin?: string | undefined;
binName?: string | undefined;
};

donationSuccessfulOptions?: {
successResponse: SuccessResponse;
upsellSuccessResponse?: SuccessResponse | undefined;
Expand All @@ -34,7 +47,9 @@ export class MockBraintreeManager implements BraintreeManagerInterface {
this.submitDonationResponse = options?.submitDonationResponse ?? 'success';
}

paymentProviders: PaymentProvidersInterface = new MockPaymentProviders();
paymentProviders: PaymentProvidersInterface = new MockPaymentProviders({
braintreeManager: this,
});
instance: PromisedSingleton<braintree.Client> = new PromisedSingleton<braintree.Client>({
generator: new Promise(resolve => {
resolve(new MockBraintreeClient());
Expand Down Expand Up @@ -65,6 +80,8 @@ export class MockBraintreeManager implements BraintreeManagerInterface {
throw 'oh no';
}

this.submitDonationOptions = options;

if (this.submitDonationResponse === 'success') {
const response = new SuccessResponse({
paymentMethodNonce: options.nonce,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import {
SuccessResponse,
PaymentProvider,
DonationPaymentInfo,
BillingInfo,
CustomerInfo,
DonationResponse,
} from '@internetarchive/donation-form-data-models';
import { UpsellModalCTAMode } from '../../src/modals/upsell-modal-content';
import { DonationFlowModalManagerInterface } from '../../src/payment-flow-handlers/donation-flow-modal-manager';

export class MockDonationFlowModalManager implements DonationFlowModalManagerInterface {
closeModalCalled = false;
showProcessingModalCalled = false;
showThankYouModalOptions?: {
successResponse: SuccessResponse;
upsellSuccessResponse?: SuccessResponse | undefined;
};
showErrorModalOptions?: {
message: string;
userClosedModalCallback?: (() => void) | undefined;
};
showUpsellModalOptions?: {
oneTimeAmount: number;
ctaMode?: UpsellModalCTAMode | undefined;
yesSelected?: ((amount: number) => void) | undefined;
noSelected?: (() => void) | undefined;
amountChanged?: ((amount: number) => void) | undefined;
userClosedModalCallback?: (() => void) | undefined;
};
startDonationSubmissionFlowOptions?: {
nonce: string;
paymentProvider: PaymentProvider;
donationInfo: DonationPaymentInfo;
billingInfo: BillingInfo;
customerInfo: CustomerInfo;
upsellOnetimeTransactionId?: string | undefined;
customerId?: string | undefined;
recaptchaToken?: string | undefined;
bin?: string | undefined;
binName?: string | undefined;
};
handleSuccessfulDonationResponseDonationInfo?: DonationPaymentInfo;
handleSuccessfulDonationResponseResponse?: SuccessResponse;

closeModal(): void {
this.closeModalCalled = true;
}
showProcessingModal(): void {
this.showProcessingModalCalled = true;
}
showThankYouModal(options: {
successResponse: SuccessResponse;
upsellSuccessResponse?: SuccessResponse | undefined;
}): void {
this.showThankYouModalOptions = options;
}
showErrorModal(options: {
message: string;
userClosedModalCallback?: (() => void) | undefined;
}): void {
this.showErrorModalOptions = options;
}
async showUpsellModal(options: {
oneTimeAmount: number;
ctaMode?: UpsellModalCTAMode | undefined;
yesSelected?: ((amount: number) => void) | undefined;
noSelected?: (() => void) | undefined;
amountChanged?: ((amount: number) => void) | undefined;
userClosedModalCallback?: (() => void) | undefined;
}): Promise<void> {
this.showUpsellModalOptions = options;
}
async startDonationSubmissionFlow(options: {
nonce: string;
paymentProvider: PaymentProvider;
donationInfo: DonationPaymentInfo;
billingInfo: BillingInfo;
customerInfo: CustomerInfo;
upsellOnetimeTransactionId?: string | undefined;
customerId?: string | undefined;
recaptchaToken?: string | undefined;
bin?: string | undefined;
binName?: string | undefined;
}): Promise<DonationResponse | undefined> {
this.startDonationSubmissionFlowOptions = options;
return undefined;
}
handleSuccessfulDonationResponse(
donationInfo: DonationPaymentInfo,
response: SuccessResponse,
): void {
this.handleSuccessfulDonationResponseDonationInfo = donationInfo;
this.handleSuccessfulDonationResponseResponse = response;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,19 @@ import { DonationPaymentInfo } from '@internetarchive/donation-form-data-models'
import { MockApplePayClient } from '../../payment-clients/mock-applepay-client';
import { ApplePaySessionDataSource } from '../../../../src/braintree-manager/payment-providers/apple-pay/apple-pay-session-datasource';
import { ApplePayHandlerInterface } from '../../../../src/braintree-manager/payment-providers/apple-pay/apple-pay-interface';
import { BraintreeManagerInterface } from '../../../../src/braintree-manager/braintree-interfaces';
import { MockApplePaySession } from '../../payment-clients/mock-applepay-session';
import { ApplePaySessionDataSourceInterface } from '../../../../src/braintree-manager/payment-providers/apple-pay/apple-pay-session-datasource-interface';

export class MockApplePayHandler implements ApplePayHandlerInterface {
dataSource?: ApplePaySessionDataSourceInterface;

private braintreeManager: BraintreeManagerInterface;

constructor(braintreeManager: BraintreeManagerInterface) {
this.braintreeManager = braintreeManager;
}

instance: PromisedSingleton<any> = new PromisedSingleton<braintree.ApplePay>({
generator: new Promise<any>(resolve => {
resolve(new MockApplePayClient());
Expand All @@ -17,10 +28,17 @@ export class MockApplePayHandler implements ApplePayHandlerInterface {
throw new Error('Method not implemented.');
}

createPaymentRequest(
async createPaymentRequest(
e: Event,
donationInfo: DonationPaymentInfo,
): Promise<ApplePaySessionDataSource> {
throw new Error('Method not implemented.');
): Promise<ApplePaySessionDataSourceInterface> {
const session = new MockApplePaySession();
this.dataSource = new ApplePaySessionDataSource({
donationInfo: donationInfo,
session: session,
applePayInstance: 'foo',
braintreeManager: this.braintreeManager,
});
return this.dataSource;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { ApplePayHandlerInterface } from '../../../src/braintree-manager/payment
import { PayPalHandlerInterface } from '../../../src/braintree-manager/payment-providers/paypal/paypal-interface';
import { GooglePayHandlerInterface } from '../../../src/braintree-manager/payment-providers/google-pay-interface';
import { VenmoHandlerInterface } from '../../../src/braintree-manager/payment-providers/venmo-interface';
import { BraintreeManagerInterface } from '../../../src/braintree-manager/braintree-interfaces';

export class MockPaymentProviders implements PaymentProvidersInterface {
creditCardHandler: PromisedSingleton<CreditCardHandlerInterface> = new PromisedSingleton<
Expand All @@ -29,7 +30,7 @@ export class MockPaymentProviders implements PaymentProvidersInterface {
ApplePayHandlerInterface
>({
generator: new Promise<ApplePayHandlerInterface>(resolve => {
resolve(new MockApplePayHandler());
resolve(new MockApplePayHandler(this.braintreeManager));
}),
});

Expand Down Expand Up @@ -57,12 +58,15 @@ export class MockPaymentProviders implements PaymentProvidersInterface {
}),
});

constructor(options?: {
constructor(options: {
braintreeManager: BraintreeManagerInterface;
mockHostedFieldTokenizePayload?: braintree.HostedFieldsTokenizePayload;
}) {
this.braintreeManager = options.braintreeManager;
this.mockHostedFieldTokenizePayload =
options?.mockHostedFieldTokenizePayload ?? mockHostedFieldTokenizePayload;
options.mockHostedFieldTokenizePayload ?? mockHostedFieldTokenizePayload;
}

mockHostedFieldTokenizePayload: braintree.HostedFieldsTokenizePayload;
braintreeManager: BraintreeManagerInterface;
}
Loading