Skip to content
Merged
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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "processout.js",
"version": "1.9.14",
"version": "1.9.15",
"description": "ProcessOut.js is a JavaScript library for ProcessOut's payment processing API.",
"scripts": {
"build:processout": "tsc -p src/processout && uglifyjs --compress --keep-fnames --ie8 dist/processout.js -o dist/processout.js",
Expand Down
10 changes: 9 additions & 1 deletion src/dynamic-checkout/clients/apple-pay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,20 @@ module ProcessOut {
),
)

session.onpaymentauthorizedPostprocess = () =>
session.onpaymentauthorizedPostprocess = () => {
DynamicCheckoutEventsUtils.dispatchPaymentSubmittedEvent({
payment_method_name: "apple_pay",
payment_method_display_name: this.getApplePayPaymentMethodName(invoiceData),
invoice_id: this.paymentConfig.invoiceId,
return_url: this.paymentConfig.invoiceDetails.return_url || null,
})

DynamicCheckoutEventsUtils.dispatchApplePayAuthorizedPostProcessEvent(
this.paymentConfig.invoiceId,
this.getApplePayPaymentMethodName(invoiceData),
this.paymentConfig.invoiceDetails.return_url || null,
)
}

return session
}
Expand Down
7 changes: 7 additions & 0 deletions src/dynamic-checkout/clients/google-pay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,13 @@ module ProcessOut {
this.googleClient
.loadPaymentData(this.paymentRequest)
.then(paymentData => {
DynamicCheckoutEventsUtils.dispatchPaymentSubmittedEvent({
payment_method_name: "google_pay",
payment_method_display_name: this.getGooglePayPaymentMethodName(invoiceData),
invoice_id: this.paymentConfig.invoiceId,
return_url: this.paymentConfig.invoiceDetails.return_url || null,
})

const paymentToken = new PaymentToken(
TokenType.GooglePay,
JSON.parse(paymentData.paymentMethodData.tokenizationData.token),
Expand Down
118 changes: 118 additions & 0 deletions test/dynamic-checkout/wallet-events.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import { beforeEach, describe, expect, it, vi } from "vitest"
import { CapturedEvent, loadDynamicCheckout } from "../support/loadNamespace"

const PAYMENT_SUBMITTED = "processout_dynamic_checkout_payment_submitted"

let ProcessOut: Record<string, any>
let dispatchedEvents: CapturedEvent[]

beforeEach(() => {
const loaded = loadDynamicCheckout()
ProcessOut = loaded.namespace
dispatchedEvents = loaded.dispatchedEvents
})

function createPaymentConfig() {
const paymentConfig = new ProcessOut.DynamicCheckoutPaymentConfig({
projectId: "proj_test",
invoiceId: "iv_test",
})

paymentConfig.setInvoiceDetails({ payment_methods: [], return_url: "https://merchant.test" })

return paymentConfig
}

function getEventTypes() {
return dispatchedEvents.map(event => event.type)
}

describe("Google Pay", () => {
const invoiceData = {
id: "iv_test",
payment_methods: [{ type: "googlepay", display: { name: "GPay" } }],
}
const paymentData = {
paymentMethodData: { tokenizationData: { token: JSON.stringify({ signature: "sig" }) } },
}

function createClient(loadPaymentData: () => Promise<unknown>) {
const processOutInstance = { tokenize: vi.fn() }
const client = new ProcessOut.GooglePayClient(processOutInstance, createPaymentConfig())
client.googleClient = { loadPaymentData }

return { client, processOutInstance }
}

it("dispatches payment_submitted before tokenizing once the user approves", async () => {
const { client, processOutInstance } = createClient(() => Promise.resolve(paymentData))
processOutInstance.tokenize.mockImplementation(() => {
expect(getEventTypes()).toEqual([PAYMENT_SUBMITTED])
})

client.makePayment(invoiceData, () => ({}))
await vi.waitFor(() => expect(processOutInstance.tokenize).toHaveBeenCalledOnce())

expect(dispatchedEvents[0].detail).toEqual({
payment_method_name: "google_pay",
payment_method_display_name: "GPay",
invoice_id: "iv_test",
return_url: "https://merchant.test",
})
})

it("does not dispatch payment_submitted when the payment sheet is dismissed", async () => {
const { client, processOutInstance } = createClient(() =>
Promise.reject({ statusCode: "CANCELED" }),
)

client.makePayment(invoiceData, () => ({}))
await vi.waitFor(() => expect(dispatchedEvents).toHaveLength(1))

expect(getEventTypes()).not.toContain(PAYMENT_SUBMITTED)
expect(processOutInstance.tokenize).not.toHaveBeenCalled()
})
})

describe("Apple Pay", () => {
const invoiceData = {
id: "iv_test",
name: "Order",
amount: "10.00",
currency: "USD",
payment_methods: [
{
type: "applepay",
display: { name: "Apple Pay (CAT)" },
applepay: { country_code: "US", merchant_capabilities: [], merchant_id: "merchant.test" },
},
],
}

function createSession() {
const processOutInstance = { applePay: { newSession: () => ({}) } }
const client = new ProcessOut.ApplePayClient(processOutInstance, createPaymentConfig())
client.getSupportedNetworks = () => []

return client.createApplePaySession(invoiceData)
}

it("dispatches payment_submitted when the user authorizes the payment", () => {
const session = createSession()

expect(dispatchedEvents).toHaveLength(0)

session.onpaymentauthorizedPostprocess()

expect(getEventTypes()).toEqual([
PAYMENT_SUBMITTED,
"processout_dynamic_checkout_apple_pay_authorized_post_process",
])
expect(dispatchedEvents[0].detail).toEqual({
payment_method_name: "apple_pay",
payment_method_display_name: "Apple Pay (CAT)",
invoice_id: "iv_test",
return_url: "https://merchant.test",
})
})
})
6 changes: 6 additions & 0 deletions test/support/loadNamespace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,12 @@ export function loadDynamicCheckout(): DynamicCheckoutNamespace {
compile("src/dynamic-checkout/utils/status-messages.ts"),
compile("src/dynamic-checkout/config/payment-config.ts"),
compile("src/dynamic-checkout/utils/events.ts"),
`const { DynamicCheckoutEventsUtils } = ProcessOut;`,
// Core SDK types the Google Pay client constructs; not part of the Dynamic Checkout bundle.
`const TokenType = { GooglePay: "googlepay" };`,
`function PaymentToken(type, token) { this.type = type; this.token = token; }`,
compile("src/dynamic-checkout/clients/google-pay.ts"),
compile("src/dynamic-checkout/clients/apple-pay.ts"),
]

const dispatchedEvents: CapturedEvent[] = []
Expand Down
Loading