chromium/components/test/data/payments/payment_handler.js

/*
 * Copyright 2019 The Chromium Authors
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

const DEFAULT_METHOD_NAME = window.location.origin;
const SW_SRC_URL = 'payment_handler_sw.js';

let methodName = DEFAULT_METHOD_NAME;
var request;

/**
 * Uninstalls the payment handler.
 * @param {string} swSrcUrlOverride - Optional service worker JavaScript file
 * URL.
 * @return {Promise<string>} - 'success' or error message on failure.
 */
async function uninstall(swSrcUrlOverride) {
  let swSrcUrl =
      (swSrcUrlOverride !== undefined) ? swSrcUrlOverride : SW_SRC_URL;
  try {
    let registration = await navigator.serviceWorker.getRegistration(swSrcUrl);
    if (!registration) {
      return 'The Payment handler has not been installed yet.';
    }
    await registration.unregister();
    return 'success';
  } catch (e) {
    return e.toString();
  }
}

/**
 * Delegates handling of the provided options to the payment handler.
 * @param {Array<string>} delegations The list of payment options to delegate.
 * @return {Promise<string>} - 'success' or error message on failure.
 */
async function enableDelegations(delegations) {
  try {
    await navigator.serviceWorker.ready;
    let registration =
        await navigator.serviceWorker.getRegistration(SW_SRC_URL);
    if (!registration) {
      return 'The payment handler is not installed.';
    }
    if (!registration.paymentManager) {
      return 'PaymentManager API not found.';
    }
    if (!registration.paymentManager.enableDelegations) {
      return 'PaymentManager does not support enableDelegations method';
    }

    await registration.paymentManager.enableDelegations(delegations);
    return 'success';
  } catch (e) {
    return e.toString();
  }
}

/**
 * Launches the payment handler.
 * @param {string} methodNameOverride - Optional payment method identifier.
 * @return {Promise<string>} - 'success' or error message on failure.
 */
async function launch(methodNameOverride) {
  let method =
      (methodNameOverride !== undefined) ? methodNameOverride : methodName;
  try {
    const request = new PaymentRequest([{supportedMethods: method}], {
      total: {label: 'Total', amount: {currency: 'USD', value: '0.01'}},
    });
    const response = await request.show();
    await response.complete('success');
    return 'success';
  } catch (e) {
    return e.toString();
  }
}

/**
 * Launches the payment handler without waiting for a response to be returned.
 * @param {string} methodNameOverride - The payment method to launch. If not
 *     specified, the global methodName set from install() will be used.
 * @param {string} windowPage - The page to load in the payment handler window.
 * @return {string} The 'success' or error message.
 */
function launchWithoutWaitForResponse(methodNameOverride, windowPage) {
  let method =
      (methodNameOverride !== undefined) ? methodNameOverride : methodName;
  return launchWithoutWaitForResponseWithMethods(
      [{supportedMethods: method, data: {'windowPage': windowPage}}]);
}

/**
 * Launches the payment handler without waiting for a response to be returned.
 * @param {sequence<PaymentMethodData>} methodData An array of payment method
 *        objects.
 * @return {string} The 'success' or error message.
 */
function launchWithoutWaitForResponseWithMethods(methodData) {
  try {
    request = new PaymentRequest(methodData, {
      total: {label: 'Total', amount: {currency: 'USD', value: '0.01'}},
    });
    request.show();
    return 'success';
  } catch (e) {
    return e.toString();
  }
}

/**
 * Aborts the on-going payment request.
 * @return {Promise<string>} - 'success' or error message on failure.
 */
async function abort() {
  try {
    await request.abort();
    return 'success';
  } catch (e) {
    return e.toString();
  }
}

var paymentOptions = null;

/**
 * Creates a payment request with required information and calls request.show()
 * to invoke payment sheet UI. To ensure that UI gets shown two payment methods
 * are supported: One URL-based and one 'basic-card'.
 * @param {Object} options - The list of requested paymentOptions.
 * @param {string} paymentMethod - A URL-based payment method identifier.
 * @return {Promise<string>} - The 'success' or error message.
 */
async function paymentRequestWithOptions(options, paymentMethod) {
  paymentOptions = options;
  if (!paymentMethod) {
    return 'Payment method required';
  }
  try {
    const request = new PaymentRequest([{supportedMethods: paymentMethod}],
      {
        total: {
          label: 'Total',
          amount: {
            currency: 'USD',
            value: '0.01',
          },
        },
        shippingOptions: [{
          id: 'freeShippingOption',
          label: 'Free global shipping',
          amount: {
            currency: 'USD',
            value: '0',
          },
          selected: true,
        }],
      },
      options);

    const response = await request.show();
    return validatePaymentResponse(response);
  } catch (e) {
    return e.toString();
  }
}

/**
 * Validates the response received from payment handler.
 * @param {Object} response - The response received from payment handler.
 * @param {Promise<string>} - Either 'success' or an error message.
 */
async function validatePaymentResponse(response) {
  try {
    var isValid = true;
    if (paymentOptions.requestShipping) {
      isValid = ('freeShippingOption' === response.shippingOption) &&
          ('Reston' === response.shippingAddress.city) &&
          ('US' === response.shippingAddress.country) &&
          ('20190' === response.shippingAddress.postalCode) &&
          ('VA' === response.shippingAddress.region);
    }

    isValid = isValid &&
        (!paymentOptions.requestPayerName ||
        ('John Smith' === response.payerName)) &&
        (!paymentOptions.requestPayerEmail ||
        ('[email protected]' === response.payerEmail)) &&
        (!paymentOptions.requestPayerPhone ||
        ('+15555555555' === response.payerPhone));

    await response.complete(isValid ? 'success' : 'fail');
    return 'success';
  } catch (e) {
    return e.toString();
  }
}