Skip to content

Commit

Permalink
Move post-success into DonationSubmitter
Browse files Browse the repository at this point in the history
  • Loading branch information
wwahammy committed Sep 14, 2022
1 parent 2f32bc6 commit 1051541
Show file tree
Hide file tree
Showing 7 changed files with 164 additions and 35 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@

// License: LGPL-3.0-or-later
export const paymentSucceededPlausible = jest.fn();
54 changes: 51 additions & 3 deletions client/js/nonprofits/donate/DonationSubmitter/index.spec.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
// License: LGPL-3.0-or-later
import DonationSubmitter from '.';
jest.mock('./plausibleWrapper')

import {paymentSucceededPlausible} from './plausibleWrapper';

const mockedPaymentSucceeededPlausible = paymentSucceededPlausible as jest.Mock;

describe('DonationSubmitter', () => {

beforeEach(() => {
mockedPaymentSucceeededPlausible.mockClear();
})

function SetupDonationSubmitter(updated=jest.fn()) {
function SetupDonationSubmitter(updated=jest.fn(), getPlausible=jest.fn()) {
const ret = {
submitter: new DonationSubmitter(),
submitter: new DonationSubmitter(getPlausible),
updated,
getPlausible
};

ret.submitter.addEventListener('updated', ret.updated)
Expand Down Expand Up @@ -52,6 +61,12 @@ describe('DonationSubmitter', () => {
const {updated} = prepare()
expect(updated).not.toHaveBeenCalled()
})

it('has not called plausible', () => {
prepare();
expect(mockedPaymentSucceeededPlausible).not.toHaveBeenCalled();

});
})

describe("when beginSubmit and then savedCard", () => {
Expand Down Expand Up @@ -107,6 +122,12 @@ describe('DonationSubmitter', () => {

expect(updated).toHaveBeenCalledTimes(2);
})

it('has not called plausible', () => {
prepare();
expect(mockedPaymentSucceeededPlausible).not.toHaveBeenCalled();

});
})

describe("when beginSubmit and then completed", () => {
Expand Down Expand Up @@ -164,6 +185,11 @@ describe('DonationSubmitter', () => {
expect(updated).toHaveBeenCalledTimes(3)
})

it('has called plausible', () => {
prepare();
expect(mockedPaymentSucceeededPlausible).toHaveBeenCalled();

});
})

describe("when beginSubmit and then errored", () => {
Expand Down Expand Up @@ -222,6 +248,12 @@ describe('DonationSubmitter', () => {
expect(updated).toHaveBeenCalledTimes(2);

})

it('has not called plausible', () => {
prepare();
expect(mockedPaymentSucceeededPlausible).not.toHaveBeenCalled();

});
})

describe("when savedCard and then errored", () => {
Expand Down Expand Up @@ -279,6 +311,12 @@ describe('DonationSubmitter', () => {

expect(updated).toHaveBeenCalledTimes(3);
})

it('has not called plausible', () => {
prepare();
expect(mockedPaymentSucceeededPlausible).not.toHaveBeenCalled();

});
});


Expand Down Expand Up @@ -330,13 +368,18 @@ describe('DonationSubmitter', () => {
expect(updated).toHaveBeenCalledTimes(4);
});

it('has not called updated getPlausible', () => {
const {getPlausible} = prepare();

expect(getPlausible).not.toHaveBeenCalled();
});
})

describe("when errored and then re-attempted", () => {
const error = "Error message";
const donationResult:any = { charge: undefined };
function prepare(): ReturnType<typeof SetupDonationSubmitter> {
const mocked = SetupDonationSubmitter(jest.fn());
const mocked = SetupDonationSubmitter(jest.fn(), jest.fn());
mocked.submitter.reportBeginSubmit();
mocked.submitter.reportSavedCard();
mocked.submitter.reportError(error);
Expand Down Expand Up @@ -381,6 +424,11 @@ describe('DonationSubmitter', () => {

expect(updated).toHaveBeenCalledTimes(6);
});

it('has called plausible', () => {
prepare();
expect(mockedPaymentSucceeededPlausible).toHaveBeenCalled();
});
})


Expand Down
15 changes: 14 additions & 1 deletion client/js/nonprofits/donate/DonationSubmitter/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@

import StateManager, {DonationResult, EventObjects} from "./StateManager";

import {GetPlausible, paymentSucceededPlausible} from './plausibleWrapper';

export default class DonationSubmitter implements EventTarget {


private stateManager = new StateManager();

private eventTarget = new EventTarget();

constructor() {
constructor(private readonly _getPlausible?:GetPlausible) {

Object.bind(this, this.handleBeginSubmit);
Object.bind(this, this.handleSavedCard);
Expand Down Expand Up @@ -45,6 +47,16 @@ export default class DonationSubmitter implements EventTarget {
return this.stateManager.result;
}

private postSuccess():void {

try {
paymentSucceededPlausible({getPlausible: this._getPlausible, result: this.result});
}
catch(e) {
console.error(e)
}
}

public reportBeginSubmit():void {
this.stateManager.reportBeginSubmit();
}
Expand Down Expand Up @@ -72,6 +84,7 @@ export default class DonationSubmitter implements EventTarget {
}

private handleCompleted(_evt: Event) {
this.postSuccess();
this.dispatchEvent(new Event('updated'));
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// License: LGPL-3.0-or-later
import {paymentSucceededPlausible} from './plausibleWrapper';


describe('plausibleWrapper', () => {
describe('paymentSucceededPlausible', () => {
it('completes if getPlausible is undefined', () => {
expect(() => paymentSucceededPlausible({})).not.toThrow();
})

it('completes if getPlausible is returns undefined', () => {
expect(() => paymentSucceededPlausible({getPlausible: () => undefined})).not.toThrow();
})

describe('completes if getPlausible is defined but result is', () => {
it('undefined', () => {
const realPlausibleFunc = jest.fn();
expect(() => paymentSucceededPlausible({getPlausible: () => realPlausibleFunc})).not.toThrow();

expect(realPlausibleFunc).toHaveBeenCalledWith('payment_succeeded', {
props: {
amount: undefined,
}});

})

it('exists but doesnt have a charge', () => {
const realPlausibleFunc = jest.fn();
expect(() => paymentSucceededPlausible({getPlausible: () => realPlausibleFunc, result:{}})).not.toThrow();

expect(realPlausibleFunc).toHaveBeenCalledWith('payment_succeeded', {
props: {
amount: undefined,
}});

});

it('exists but doesnt have an amount', () => {
const realPlausibleFunc = jest.fn();
expect(() => paymentSucceededPlausible({getPlausible: () => realPlausibleFunc, result:{charge:{}}})).not.toThrow();

expect(realPlausibleFunc).toHaveBeenCalledWith('payment_succeeded', {
props: {
amount: undefined,
}});

});

it('exists and has an amount', () => {
const realPlausibleFunc = jest.fn();
expect(() => paymentSucceededPlausible({getPlausible: () => realPlausibleFunc, result:{charge:{amount: 1000}}})).not.toThrow();

expect(realPlausibleFunc).toHaveBeenCalledWith('payment_succeeded', {
props: {
amount: 10,
}});

})
})
})
});
25 changes: 25 additions & 0 deletions client/js/nonprofits/donate/DonationSubmitter/plausibleWrapper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// License: LGPL-3.0-or-later
export interface PlausibleFunction {
(eventType: string, val: any): void
}

export interface GetPlausible {

(): PlausibleFunction | undefined
}

/**
* Notifies plausible that the payment has been created
*/
export function paymentSucceededPlausible({ getPlausible, result }: { getPlausible?: GetPlausible, result?: { charge?: { amount?: number } } }) {

const plausibleFunction = getPlausible && getPlausible();

if (plausibleFunction) {
plausibleFunction('payment_succeeded', {
props: {
amount: result?.charge?.amount && (result.charge.amount / 100)
}
});
}
}
29 changes: 4 additions & 25 deletions client/js/nonprofits/donate/payment-step.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,11 @@ function init(state) {
const coverFees$ = flyd.map(params => (params.manual_cover_fees || params.hide_cover_fees_option) ? false : true, params$)

const hideCoverFeesOption$ = flyd.map(params => params.hide_cover_fees_option, params$)

const donationAmountCalculator = new DonationAmountCalculator(app.nonprofit.feeStructure);
const donationSubmitter = new DonationSubmitter()

const donationSubmitter = new DonationSubmitter(() => window['plausible'])


// Give a donation of value x, this returns x + estimated fees (using fee coverage formula) if fee coverage is selected OR
// x if fee coverage is not selected
Expand All @@ -49,7 +51,6 @@ function init(state) {
function handleDonationAmountCalcEvent(e) {
updateFromDonationAmountCalculator();
}

state.loading$ = flyd.stream();
state.error$ = flyd.stream();
// Control progress bar for card payment
Expand Down Expand Up @@ -96,14 +97,11 @@ function init(state) {
donationAmountCalculator.removeEventListener('updated', handleDonationAmountCalcEvent)
donationSubmitter.removeEventListener('updated', handleDonationSubmitterChanged)
}

flyd.combine((donation$, coverFees$) => {
donationAmountCalculator.inputAmount = donation$().amount
donationAmountCalculator.coverFees = coverFees$();
}, [state.donation$, coverFees$]);




state.cardForm = cardForm.init({
path: '/cards', card$, payload$, donationTotal$: state.donationTotal$, coverFees$, potentialFees$: state.potentialFees$,
Expand Down Expand Up @@ -174,7 +172,6 @@ function init(state) {
flyd.map((error) => {
donationSubmitter.reportError(error);
}, state.cardForm.error$)

flyd.map((error) => {
donationSubmitter.reportError(error);
}, state.sepaForm.error$)
Expand All @@ -185,11 +182,6 @@ function init(state) {
, state.paid$
)

flyd.map(
R.apply((donationResponse) => postSuccess(donationResp$))
, state.paid$
)

onInit();

return state
Expand Down Expand Up @@ -222,19 +214,6 @@ const postTracking = (utmParams, donationResponse) => {
}
}

const postSuccess = (donationResponse) => {
try {
const plausible = window['plausible'];
if (plausible) {
const resp = donationResponse()
plausible('payment_succeeded', {props: {amount: resp && resp.charge && resp.charge.amount && (resp.charge.amount / 100)}});
}
}
catch(e) {
console.error(e)
}
}

var posting = false // hack switch to prevent any kind of charge double post
// Post either a recurring or one-time donation
const postDonation = (donation) => {
Expand Down
12 changes: 6 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 1051541

Please sign in to comment.