Source/WebCore/ChangeLog

 12017-10-20 Andy Estes <aestes@apple.com>
 2
 3 [Payment Request] Resolve PaymentRequest.show()'s accept promise when a payment is authorized
 4 https://bugs.webkit.org/show_bug.cgi?id=178609
 5
 6 Reviewed by Alex Christensen.
 7
 8 This patch implements the logic for resolving PaymentRequest.show()'s accept promise when
 9 the user authorizes a payment, and implements PaymentResponse.complete().
 10
 11 Tests: http/tests/paymentrequest/payment-address-attributes-and-toJSON-method.https.html
 12 http/tests/paymentrequest/payment-response-complete-method.https.html
 13 http/tests/paymentrequest/payment-response-methodName-attribute.https.html
 14 http/tests/paymentrequest/payment-response-payerEmail-attribute.https.html
 15 http/tests/paymentrequest/payment-response-payerName-attribute.https.html
 16 http/tests/paymentrequest/payment-response-payerPhone-attribute.https.html
 17
 18 * DerivedSources.make:
 19 * Modules/applepay/ApplePayPaymentContact.h:
 20 * Modules/applepay/Payment.h:
 21 (WebCore::Payment::Payment): Deleted.
 22 (WebCore::Payment::pkPayment const): Deleted.
 23 * Modules/applepay/PaymentContact.h:
 24 (WebCore::PaymentContact::PaymentContact): Deleted.
 25 (WebCore::PaymentContact::pkContact const): Deleted.
 26 * Modules/applepay/cocoa/PaymentContactCocoa.mm:
 27 (WebCore::convert):
 28 * Modules/applepay/paymentrequest/ApplePayPaymentHandler.cpp:
 29 (WebCore::ApplePayPaymentHandler::hasActiveSession):
 30 (WebCore::ApplePayPaymentHandler::ApplePayPaymentHandler):
 31 (WebCore::ApplePayPaymentHandler::document):
 32 (WebCore::ApplePayPaymentHandler::paymentCoordinator):
 33 (WebCore::ApplePayPaymentHandler::convertData):
 34 (WebCore::ApplePayPaymentHandler::show):
 35 (WebCore::ApplePayPaymentHandler::hide):
 36 (WebCore::ApplePayPaymentHandler::canMakePayment):
 37 (WebCore::ApplePayPaymentHandler::complete):
 38 (WebCore::convert):
 39 (WebCore::ApplePayPaymentHandler::didAuthorizePayment):
 40 (WebCore::ApplePayPaymentHandler::didSelectShippingMethod):
 41 (WebCore::ApplePayPaymentHandler::didSelectShippingContact):
 42 * Modules/applepay/paymentrequest/ApplePayPaymentHandler.h:
 43 * Modules/paymentrequest/PaymentAddress.h:
 44 * Modules/paymentrequest/PaymentAddress.idl:
 45 * Modules/paymentrequest/PaymentHandler.cpp:
 46 (WebCore::PaymentHandler::create):
 47 * Modules/paymentrequest/PaymentHandler.h:
 48 * Modules/paymentrequest/PaymentRequest.cpp:
 49 (WebCore::PaymentRequest::show):
 50 (WebCore::PaymentRequest::stop):
 51 (WebCore::PaymentRequest::canMakePayment):
 52 (WebCore::PaymentRequest::canSuspendForDocumentSuspension const):
 53 (WebCore::PaymentRequest::shippingAddressChanged):
 54 (WebCore::PaymentRequest::shippingOptionChanged):
 55 (WebCore::PaymentRequest::accept):
 56 (WebCore::PaymentRequest::complete):
 57 * Modules/paymentrequest/PaymentRequest.h:
 58 * Modules/paymentrequest/PaymentResponse.cpp:
 59 (WebCore::PaymentResponse::PaymentResponse):
 60 (WebCore::PaymentResponse::complete):
 61 * Modules/paymentrequest/PaymentResponse.h:
 62 * WebCore.xcodeproj/project.pbxproj:
 63 * testing/Internals.cpp:
 64 (WebCore::Internals::Internals):
 65 (WebCore::Internals::mockPaymentCoordinator const):
 66 * testing/Internals.h:
 67 * testing/Internals.idl:
 68 * testing/MockPayment.h: Copied from Source/WebCore/Modules/paymentrequest/PaymentResponse.cpp.
 69 * testing/MockPaymentAddress.h: Copied from Source/WebCore/Modules/paymentrequest/PaymentResponse.cpp.
 70 * testing/MockPaymentAddress.idl: Copied from Source/WebCore/Modules/paymentrequest/PaymentResponse.cpp.
 71 * testing/MockPaymentContact.h: Copied from Source/WebCore/Modules/paymentrequest/PaymentResponse.cpp.
 72 * testing/MockPaymentCoordinator.cpp:
 73 (WebCore::MockPaymentCoordinator::canMakePaymentsWithActiveCard):
 74 (WebCore::MockPaymentCoordinator::openPaymentSetup):
 75 (WebCore::dispatchIfShowing):
 76 (WebCore::MockPaymentCoordinator::showPaymentUI):
 77 (WebCore::MockPaymentCoordinator::completeMerchantValidation):
 78 (WebCore::MockPaymentCoordinator::completePaymentSession):
 79 (WebCore::MockPaymentCoordinator::abortPaymentSession):
 80 (WebCore::MockPaymentCoordinator::cancelPaymentSession):
 81 (WebCore::MockPaymentCoordinator::paymentCoordinatorDestroyed):
 82 * testing/MockPaymentCoordinator.h:
 83 * testing/MockPaymentCoordinator.idl: Copied from Source/WebCore/Modules/paymentrequest/PaymentResponse.cpp.
 84
1852017-10-20 Keith Miller <keith_miller@apple.com>
286
387 Unreviewed, fix windows build.

Source/WebCore/DerivedSources.make

@@JS_BINDING_IDLS = \
908908 $(WebCore)/testing/MockCDMFactory.idl \
909909 $(WebCore)/testing/MockContentFilterSettings.idl \
910910 $(WebCore)/testing/MockPageOverlay.idl \
 911 $(WebCore)/testing/MockPaymentAddress.idl \
 912 $(WebCore)/testing/MockPaymentCoordinator.idl \
911913 $(WebCore)/testing/TypeConversions.idl \
912914 $(WebCore)/workers/AbstractWorker.idl \
913915 $(WebCore)/workers/DedicatedWorkerGlobalScope.idl \

Source/WebCore/Modules/applepay/ApplePayPaymentContact.h

@@struct ApplePayPaymentContact {
3838 String emailAddress;
3939 String givenName;
4040 String familyName;
 41 String localizedName;
4142 String phoneticGivenName;
4243 String phoneticFamilyName;
 44 String localizedPhoneticName;
4345 std::optional<Vector<String>> addressLines;
4446 String subLocality;
4547 String locality;

Source/WebCore/Modules/applepay/Payment.h

@@namespace WebCore {
3535
3636struct ApplePayPayment;
3737
38 class Payment {
 38class WEBCORE_EXPORT Payment {
3939public:
4040 Payment() = default;
4141

@@public:
4444 {
4545 }
4646
47  ApplePayPayment toApplePayPayment() const;
 47 virtual ~Payment() = default;
 48
 49 virtual ApplePayPayment toApplePayPayment() const;
4850
4951 PKPayment *pkPayment() const { return m_pkPayment.get(); }
5052

Source/WebCore/Modules/applepay/PaymentContact.h

@@namespace WebCore {
3636
3737struct ApplePayPaymentContact;
3838
39 class PaymentContact {
 39class WEBCORE_EXPORT PaymentContact {
4040public:
4141 PaymentContact() = default;
4242 explicit PaymentContact(PKContact *pkContact)
4343 : m_pkContact(pkContact)
4444 {
4545 }
 46 virtual ~PaymentContact() = default;
4647
4748 static PaymentContact fromApplePayPaymentContact(unsigned version, const ApplePayPaymentContact&);
48  ApplePayPaymentContact toApplePayPaymentContact() const;
 49 virtual ApplePayPaymentContact toApplePayPaymentContact() const;
4950
5051 PKContact *pkContact() const { return m_pkContact.get(); }
5152

Source/WebCore/Modules/applepay/cocoa/PaymentContactCocoa.mm

@@static ApplePayPaymentContact convert(PKContact *contact)
189189 NSPersonNameComponents *name = contact.name;
190190 result.givenName = name.givenName;
191191 result.familyName = name.familyName;
 192 result.localizedName = [NSPersonNameComponentsFormatter localizedStringFromPersonNameComponents:name style:NSPersonNameComponentsFormatterStyleDefault options:0];
192193
193194 NSPersonNameComponents *phoneticName = name.phoneticRepresentation;
194195 result.phoneticGivenName = phoneticName.givenName;
195196 result.phoneticFamilyName = phoneticName.familyName;
 197 result.localizedPhoneticName = [NSPersonNameComponentsFormatter localizedStringFromPersonNameComponents:name style:NSPersonNameComponentsFormatterStyleDefault options:NSPersonNameComponentsFormatterPhonetic];
196198
197199 CNPostalAddress *postalAddress = contact.postalAddress;
198200 if (postalAddress.street.length) {

Source/WebCore/Modules/applepay/paymentrequest/ApplePayPaymentHandler.cpp

3131#include "ApplePayContactField.h"
3232#include "ApplePayMerchantCapability.h"
3333#include "ApplePayMerchantValidationEvent.h"
 34#include "ApplePayPayment.h"
3435#include "ApplePaySessionPaymentRequest.h"
3536#include "Document.h"
3637#include "EventNames.h"
 38#include "JSApplePayPayment.h"
3739#include "JSApplePayRequest.h"
3840#include "LinkIconCollector.h"
3941#include "MainFrame.h"
4042#include "Page.h"
 43#include "Payment.h"
 44#include "PaymentAuthorizationStatus.h"
4145#include "PaymentContact.h"
4246#include "PaymentCoordinator.h"
4347#include "PaymentRequestValidator.h"
 48#include "PaymentResponse.h"
4449#include "Settings.h"
4550
4651namespace WebCore {

@@static inline PaymentCoordinator& paymentCoordinator(Document& document)
6166
6267bool ApplePayPaymentHandler::hasActiveSession(Document& document)
6368{
64  return paymentCoordinator(document).hasActiveSession();
 69 return WebCore::paymentCoordinator(document).hasActiveSession();
6570}
6671
67 ApplePayPaymentHandler::ApplePayPaymentHandler(PaymentRequest& paymentRequest)
68  : m_paymentRequest { paymentRequest }
 72ApplePayPaymentHandler::ApplePayPaymentHandler(Document& document, const PaymentRequest::MethodIdentifier& identifier, PaymentRequest& paymentRequest)
 73 : ContextDestructionObserver { &document }
 74 , m_identifier { identifier }
 75 , m_paymentRequest { paymentRequest }
6976{
 77 ASSERT(handlesIdentifier(m_identifier));
 78}
 79
 80Document& ApplePayPaymentHandler::document()
 81{
 82 return downcast<Document>(*scriptExecutionContext());
 83}
 84
 85PaymentCoordinator& ApplePayPaymentHandler::paymentCoordinator()
 86{
 87 return WebCore::paymentCoordinator(document());
7088}
7189
7290static ExceptionOr<void> validate(const PaymentCurrencyAmount& amount, const String& expectedCurrency)

@@static ExceptionOr<ApplePaySessionPaymentRequest::ShippingMethod> convertAndVali
140158 return { WTFMove(result) };
141159}
142160
143 ExceptionOr<void> ApplePayPaymentHandler::convertData(JSC::ExecState& execState, JSC::JSValue&& data)
 161ExceptionOr<void> ApplePayPaymentHandler::convertData(JSC::JSValue&& data)
144162{
145  auto throwScope = DECLARE_THROW_SCOPE(execState.vm());
146  auto applePayRequest = convertDictionary<ApplePayRequest>(execState, WTFMove(data));
 163 auto& context = *scriptExecutionContext();
 164 auto throwScope = DECLARE_THROW_SCOPE(context.vm());
 165 auto applePayRequest = convertDictionary<ApplePayRequest>(*context.execState(), WTFMove(data));
147166 if (throwScope.exception())
148167 return Exception { ExistingExceptionError };
149168

@@ExceptionOr<void> ApplePayPaymentHandler::convertData(JSC::ExecState& execState,
151170 return { };
152171}
153172
154 ExceptionOr<void> ApplePayPaymentHandler::show(Document& document)
 173ExceptionOr<void> ApplePayPaymentHandler::show()
155174{
156175 auto validatedRequest = convertAndValidate(m_applePayRequest->version, *m_applePayRequest);
157176 if (validatedRequest.hasException())

@@ExceptionOr<void> ApplePayPaymentHandler::show(Document& document)
203222 return exception.releaseException();
204223
205224 Vector<URL> linkIconURLs;
206  for (auto& icon : LinkIconCollector { document }.iconsOfTypes({ LinkIconType::TouchIcon, LinkIconType::TouchPrecomposedIcon }))
 225 for (auto& icon : LinkIconCollector { document() }.iconsOfTypes({ LinkIconType::TouchIcon, LinkIconType::TouchPrecomposedIcon }))
207226 linkIconURLs.append(icon.url);
208227
209  paymentCoordinator(document).beginPaymentSession(*this, document.url(), linkIconURLs, request);
 228 paymentCoordinator().beginPaymentSession(*this, document().url(), linkIconURLs, request);
210229 return { };
211230}
212231
213 void ApplePayPaymentHandler::hide(Document& document)
 232void ApplePayPaymentHandler::hide()
214233{
215  paymentCoordinator(document).abortPaymentSession();
 234 paymentCoordinator().abortPaymentSession();
216235}
217236
218237static bool shouldDiscloseApplePayCapability(Document& document)

@@static bool shouldDiscloseApplePayCapability(Document& document)
224243 return document.settings().applePayCapabilityDisclosureAllowed();
225244}
226245
227 void ApplePayPaymentHandler::canMakePayment(Document& document, WTF::Function<void(bool)>&& completionHandler)
 246void ApplePayPaymentHandler::canMakePayment(Function<void(bool)>&& completionHandler)
228247{
229  if (!shouldDiscloseApplePayCapability(document)) {
230  completionHandler(paymentCoordinator(document).canMakePayments());
 248 if (!shouldDiscloseApplePayCapability(document())) {
 249 completionHandler(paymentCoordinator().canMakePayments());
231250 return;
232251 }
233252
234  paymentCoordinator(document).canMakePaymentsWithActiveCard(m_applePayRequest->merchantIdentifier, document.domain(), WTFMove(completionHandler));
 253 paymentCoordinator().canMakePaymentsWithActiveCard(m_applePayRequest->merchantIdentifier, document().domain(), WTFMove(completionHandler));
 254}
 255
 256void ApplePayPaymentHandler::complete(std::optional<PaymentComplete>&& result)
 257{
 258 if (!result) {
 259 paymentCoordinator().completePaymentSession(std::nullopt);
 260 return;
 261 }
 262
 263 PaymentAuthorizationResult authorizationResult;
 264 switch (*result) {
 265 case PaymentComplete::Fail:
 266 case PaymentComplete::Unknown:
 267 authorizationResult.status = PaymentAuthorizationStatus::Failure;
 268 authorizationResult.errors.append({ PaymentError::Code::Unknown, { }, std::nullopt });
 269 break;
 270 case PaymentComplete::Success:
 271 authorizationResult.status = PaymentAuthorizationStatus::Success;
 272 break;
 273 }
 274
 275 paymentCoordinator().completePaymentSession(WTFMove(authorizationResult));
235276}
236277
237278void ApplePayPaymentHandler::validateMerchant(const URL& validationURL)

@@void ApplePayPaymentHandler::validateMerchant(const URL& validationURL)
240281 m_paymentRequest->dispatchEvent(ApplePayMerchantValidationEvent::create(eventNames().applepayvalidatemerchantEvent, validationURL).get());
241282}
242283
 284static Ref<PaymentAddress> convert(const ApplePayPaymentContact& contact)
 285{
 286 return PaymentAddress::create(contact.countryCode, contact.addressLines.value_or(Vector<String>()), contact.administrativeArea, contact.locality, contact.subLocality, contact.postalCode, String(), String(), String(), contact.localizedName, contact.phoneNumber);
 287}
 288
 289void ApplePayPaymentHandler::didAuthorizePayment(const Payment& payment)
 290{
 291 auto applePayPayment = payment.toApplePayPayment();
 292 auto& execState = *document().execState();
 293 auto details = JSC::Strong<JSC::JSObject> { execState.vm(), asObject(toJS<IDLDictionary<ApplePayPayment>>(execState, *JSC::jsCast<JSDOMGlobalObject*>(execState.lexicalGlobalObject()), applePayPayment)) };
 294 const auto& shippingContact = applePayPayment.shippingContact.value_or(ApplePayPaymentContact());
 295 m_paymentRequest->accept(WTF::get<URL>(m_identifier).string(), WTFMove(details), convert(shippingContact), shippingContact.localizedName, shippingContact.emailAddress, shippingContact.phoneNumber);
 296}
 297
 298void ApplePayPaymentHandler::didSelectShippingMethod(const ApplePaySessionPaymentRequest::ShippingMethod& shippingMethod)
 299{
 300 m_paymentRequest->shippingOptionChanged(shippingMethod.identifier);
 301}
 302
 303void ApplePayPaymentHandler::didSelectShippingContact(const PaymentContact& shippingContact)
 304{
 305 m_paymentRequest->shippingAddressChanged(convert(shippingContact.toApplePayPaymentContact()));
 306}
 307
243308} // namespace WebCore
244309
245310#endif // ENABLE(APPLE_PAY) && ENABLE(PAYMENT_REQUEST)

Source/WebCore/Modules/applepay/paymentrequest/ApplePayPaymentHandler.h

2828#if ENABLE(APPLE_PAY) && ENABLE(PAYMENT_REQUEST)
2929
3030#include "ApplePayRequest.h"
 31#include "ContextDestructionObserver.h"
3132#include "PaymentHandler.h"
 33#include "PaymentRequest.h"
3234#include "PaymentSession.h"
3335#include <wtf/Noncopyable.h>
3436#include <wtf/Ref.h>
3537
3638namespace WebCore {
3739
38 class PaymentRequest;
 40class PaymentCoordinator;
3941
40 class ApplePayPaymentHandler final : public PaymentHandler, public PaymentSession {
 42class ApplePayPaymentHandler final : public PaymentHandler, public PaymentSession, private ContextDestructionObserver {
4143public:
4244 static bool handlesIdentifier(const PaymentRequest::MethodIdentifier&);
4345 static bool hasActiveSession(Document&);
4446
4547private:
4648 friend class PaymentHandler;
47  explicit ApplePayPaymentHandler(PaymentRequest&);
 49 explicit ApplePayPaymentHandler(Document&, const PaymentRequest::MethodIdentifier&, PaymentRequest&);
 50
 51 Document& document();
 52 PaymentCoordinator& paymentCoordinator();
4853
4954 // PaymentHandler
50  ExceptionOr<void> convertData(JSC::ExecState&, JSC::JSValue&&) final;
51  ExceptionOr<void> show(Document&) final;
52  void hide(Document&) final;
53  void canMakePayment(Document&, WTF::Function<void(bool)>&& completionHandler) final;
 55 ExceptionOr<void> convertData(JSC::JSValue&&) final;
 56 ExceptionOr<void> show() final;
 57 void hide() final;
 58 void canMakePayment(WTF::Function<void(bool)>&& completionHandler) final;
 59 void complete(std::optional<PaymentComplete>&&) final;
5460
5561 // PaymentSession
5662 void validateMerchant(const URL&) final;
57  void didAuthorizePayment(const Payment&) final { }
58  void didSelectShippingMethod(const ApplePaySessionPaymentRequest::ShippingMethod&) final { }
59  void didSelectShippingContact(const PaymentContact&) final { }
 63 void didAuthorizePayment(const Payment&) final;
 64 void didSelectShippingMethod(const ApplePaySessionPaymentRequest::ShippingMethod&) final;
 65 void didSelectShippingContact(const PaymentContact&) final;
6066 void didSelectPaymentMethod(const PaymentMethod&) final { }
6167 void didCancelPaymentSession() final { }
6268
 69 PaymentRequest::MethodIdentifier m_identifier;
6370 Ref<PaymentRequest> m_paymentRequest;
6471 std::optional<ApplePayRequest> m_applePayRequest;
6572};

Source/WebCore/Modules/paymentrequest/PaymentAddress.cpp

 1/*
 2 * Copyright (C) 2017 Apple Inc. All rights reserved.
 3 *
 4 * Redistribution and use in source and binary forms, with or without
 5 * modification, are permitted provided that the following conditions
 6 * are met:
 7 * 1. Redistributions of source code must retain the above copyright
 8 * notice, this list of conditions and the following disclaimer.
 9 * 2. Redistributions in binary form must reproduce the above copyright
 10 * notice, this list of conditions and the following disclaimer in the
 11 * documentation and/or other materials provided with the distribution.
 12 *
 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 23 * THE POSSIBILITY OF SUCH DAMAGE.
 24 */
 25
 26#include "config.h"
 27#include "PaymentAddress.h"
 28
 29#if ENABLE(PAYMENT_REQUEST)
 30
 31namespace WebCore {
 32
 33PaymentAddress::PaymentAddress(const String& country, const Vector<String>& addressLine, const String& region, const String& city, const String& dependentLocality, const String& postalCode, const String& sortingCode, const String& languageCode, const String& organization, const String& recipient, const String& phone)
 34 : m_country { country }
 35 , m_addressLine { addressLine }
 36 , m_region { region }
 37 , m_city { city }
 38 , m_dependentLocality { dependentLocality }
 39 , m_postalCode { postalCode }
 40 , m_sortingCode { sortingCode }
 41 , m_languageCode { languageCode }
 42 , m_organization { organization }
 43 , m_recipient { recipient }
 44 , m_phone { phone }
 45{
 46}
 47
 48} // namespace WebCore
 49
 50#endif // ENABLE(PAYMENT_REQUEST)

Source/WebCore/Modules/paymentrequest/PaymentAddress.h

@@namespace WebCore {
3535
3636class PaymentAddress final : public RefCounted<PaymentAddress> {
3737public:
 38 template <typename... Args> static Ref<PaymentAddress> create(Args&&... args)
 39 {
 40 return adoptRef(*new PaymentAddress(std::forward<Args>(args)...));
 41 }
 42
3843 const String& country() const { return m_country; }
3944 const Vector<String>& addressLine() const { return m_addressLine; }
4045 const String& region() const { return m_region; }

@@public:
4853 const String& phone() const { return m_phone; }
4954
5055private:
 56 PaymentAddress(const String& country, const Vector<String>& addressLine, const String& region, const String& city, const String& dependentLocality, const String& postalCode, const String& sortingCode, const String& languageCode, const String& organization, const String& recipient, const String& phone);
 57
5158 String m_country;
5259 Vector<String> m_addressLine;
5360 String m_region;

Source/WebCore/Modules/paymentrequest/PaymentAddress.idl

2626[
2727 Conditional=PAYMENT_REQUEST,
2828 EnabledBySetting=PaymentRequest,
 29 Exposed=Window,
2930 ImplementationLacksVTable,
3031 SecureContext
3132] interface PaymentAddress {

Source/WebCore/Modules/paymentrequest/PaymentHandler.cpp

3434
3535namespace WebCore {
3636
37 RefPtr<PaymentHandler> PaymentHandler::create(PaymentRequest& paymentRequest, const PaymentRequest::MethodIdentifier& identifier)
 37RefPtr<PaymentHandler> PaymentHandler::create(Document& document, PaymentRequest& paymentRequest, const PaymentRequest::MethodIdentifier& identifier)
3838{
3939#if ENABLE(APPLE_PAY)
4040 if (ApplePayPaymentHandler::handlesIdentifier(identifier))
41  return adoptRef(new ApplePayPaymentHandler(paymentRequest));
 41 return adoptRef(new ApplePayPaymentHandler(document, identifier, paymentRequest));
4242#else
 43 UNUSED_PARAM(document);
4344 UNUSED_PARAM(paymentRequest);
4445 UNUSED_PARAM(identifier);
4546#endif

Source/WebCore/Modules/paymentrequest/PaymentHandler.h

3232#include <wtf/Function.h>
3333
3434namespace JSC {
35 class ExecState;
3635class JSValue;
3736}
3837

@@class Document;
4241
4342class PaymentHandler : public virtual PaymentSessionBase {
4443public:
45  static RefPtr<PaymentHandler> create(PaymentRequest&, const PaymentRequest::MethodIdentifier&);
 44 static RefPtr<PaymentHandler> create(Document&, PaymentRequest&, const PaymentRequest::MethodIdentifier&);
4645 static bool hasActiveSession(Document&);
4746
48  virtual ExceptionOr<void> convertData(JSC::ExecState&, JSC::JSValue&&) = 0;
49  virtual ExceptionOr<void> show(Document&) = 0;
50  virtual void hide(Document&) = 0;
51  virtual void canMakePayment(Document&, WTF::Function<void(bool)>&& completionHandler) = 0;
 47 virtual ExceptionOr<void> convertData(JSC::JSValue&&) = 0;
 48 virtual ExceptionOr<void> show() = 0;
 49 virtual void hide() = 0;
 50 virtual void canMakePayment(WTF::Function<void(bool)>&& completionHandler) = 0;
 51 virtual void complete(std::optional<PaymentComplete>&&) = 0;
5252};
5353
5454} // namespace WebCore

Source/WebCore/Modules/paymentrequest/PaymentRequest.cpp

3030
3131#include "ApplePayPaymentHandler.h"
3232#include "Document.h"
 33#include "JSPaymentResponse.h"
3334#include "PaymentAddress.h"
3435#include "PaymentCurrencyAmount.h"
3536#include "PaymentDetailsInit.h"
3637#include "PaymentHandler.h"
3738#include "PaymentMethodData.h"
3839#include "PaymentOptions.h"
 40#include "PaymentResponse.h"
3941#include "ScriptController.h"
4042#include <JavaScriptCore/JSONObject.h>
4143#include <JavaScriptCore/ThrowScope.h>

@@void PaymentRequest::show(Document& document, ShowPromise&& promise)
376378 return;
377379 }
378380
379  auto handler = PaymentHandler::create(*this, paymentMethod.identifier);
 381 auto handler = PaymentHandler::create(document, *this, paymentMethod.identifier);
380382 if (!handler)
381383 continue;
382384
383  auto result = handler->convertData(*document.execState(), data.releaseReturnValue());
 385 auto result = handler->convertData(data.releaseReturnValue());
384386 if (result.hasException()) {
385387 m_showPromise->reject(result.releaseException());
386388 return;

@@void PaymentRequest::show(Document& document, ShowPromise&& promise)
395397 return;
396398 }
397399
398  auto exception = selectedPaymentHandler->show(document);
 400 auto exception = selectedPaymentHandler->show();
399401 if (exception.hasException()) {
400402 m_showPromise->reject(exception.releaseException());
401403 return;

@@void PaymentRequest::stop()
413415
414416 if (auto paymentHandler = std::exchange(m_activePaymentHandler, nullptr)) {
415417 unsetPendingActivity(this);
416  paymentHandler->hide(downcast<Document>(*scriptExecutionContext()));
 418 paymentHandler->hide();
417419 }
418420
419421 ASSERT(m_state == State::Interactive);

@@void PaymentRequest::canMakePayment(Document& document, CanMakePaymentPromise&&
445447 if (data.hasException())
446448 continue;
447449
448  auto handler = PaymentHandler::create(*this, paymentMethod.identifier);
 450 auto handler = PaymentHandler::create(document, *this, paymentMethod.identifier);
449451 if (!handler)
450452 continue;
451453
452  auto exception = handler->convertData(*document.execState(), data.releaseReturnValue());
 454 auto exception = handler->convertData(data.releaseReturnValue());
453455 if (exception.hasException())
454456 continue;
455457
456  handler->canMakePayment(document, [promise = WTFMove(promise)](bool canMakePayment) mutable {
 458 handler->canMakePayment([promise = WTFMove(promise)](bool canMakePayment) mutable {
457459 promise.resolve(canMakePayment);
458460 });
459461 return;

@@bool PaymentRequest::canSuspendForDocumentSuspension() const
478480{
479481 switch (m_state) {
480482 case State::Created:
481  case State::Closed:
482483 ASSERT(!m_activePaymentHandler);
483484 return true;
484485 case State::Interactive:
 486 case State::Closed:
485487 return !m_activePaymentHandler;
486488 }
487489}
488490
 491void PaymentRequest::shippingAddressChanged(Ref<PaymentAddress>&& shippingAddress)
 492{
 493 ASSERT(m_state == State::Interactive);
 494 m_shippingAddress = WTFMove(shippingAddress);
 495 // FIXME: run the PaymentRequest updated algorithm.
 496}
 497
 498void PaymentRequest::shippingOptionChanged(const String& shippingOption)
 499{
 500 ASSERT(m_state == State::Interactive);
 501 m_shippingOption = shippingOption;
 502 // FIXME: run the PaymentRequest updated algorithm.
 503}
 504
 505void PaymentRequest::accept(const String& methodName, JSC::Strong<JSC::JSObject>&& details, Ref<PaymentAddress>&& shippingAddress, const String& payerName, const String& payerEmail, const String& payerPhone)
 506{
 507 ASSERT(m_state == State::Interactive);
 508
 509 auto response = PaymentResponse::create(*this);
 510 response->setRequestId(m_details.id);
 511 response->setMethodName(methodName);
 512 response->setDetails(WTFMove(details));
 513
 514 if (m_options.requestShipping) {
 515 response->setShippingAddress(shippingAddress.ptr());
 516 response->setShippingOption(m_shippingOption);
 517 }
 518
 519 if (m_options.requestPayerName)
 520 response->setPayerName(payerName);
 521
 522 if (m_options.requestPayerEmail)
 523 response->setPayerEmail(payerEmail);
 524
 525 if (m_options.requestPayerPhone)
 526 response->setPayerPhone(payerPhone);
 527
 528 m_showPromise->resolve(response.get());
 529 m_state = State::Closed;
 530}
 531
 532void PaymentRequest::complete(std::optional<PaymentComplete>&& result)
 533{
 534 ASSERT(m_state == State::Closed);
 535 std::exchange(m_activePaymentHandler, nullptr)->complete(WTFMove(result));
 536}
 537
489538} // namespace WebCore
490539
491540#endif // ENABLE(PAYMENT_REQUEST)

Source/WebCore/Modules/paymentrequest/PaymentRequest.h

@@class Document;
4242class PaymentAddress;
4343class PaymentHandler;
4444class PaymentResponse;
 45enum class PaymentComplete;
4546enum class PaymentShippingType;
4647struct PaymentMethodData;
4748

@@public:
6667 const PaymentOptions& paymentOptions() const { return m_options; }
6768 const PaymentDetailsInit& paymentDetails() const { return m_details; }
6869
 70 void shippingAddressChanged(Ref<PaymentAddress>&&);
 71 void shippingOptionChanged(const String& shippingOption);
 72 void accept(const String& methodName, JSC::Strong<JSC::JSObject>&& details, Ref<PaymentAddress>&& shippingAddress, const String& payerName, const String& payerEmail, const String& payerPhone);
 73 void complete(std::optional<PaymentComplete>&&);
 74
6975 using MethodIdentifier = Variant<String, URL>;
7076 using RefCounted<PaymentRequest>::ref;
7177 using RefCounted<PaymentRequest>::deref;

Source/WebCore/Modules/paymentrequest/PaymentResponse.cpp

2828
2929#if ENABLE(PAYMENT_REQUEST)
3030
 31#include "PaymentRequest.h"
3132#include <wtf/RunLoop.h>
3233
3334namespace WebCore {
3435
35 void PaymentResponse::complete(std::optional<PaymentComplete>&&, DOMPromiseDeferred<void>&& promise)
 36PaymentResponse::PaymentResponse(PaymentRequest& request)
 37 : m_request { request }
3638{
37  promise.reject(Exception { NotSupportedError, ASCIILiteral("Not implemented") });
 39}
 40
 41PaymentResponse::~PaymentResponse() = default;
 42
 43void PaymentResponse::complete(std::optional<PaymentComplete>&& result, DOMPromiseDeferred<void>&& promise)
 44{
 45 if (m_completeCalled) {
 46 promise.reject(Exception { InvalidStateError });
 47 return;
 48 }
 49
 50 m_completeCalled = true;
 51 m_request->complete(WTFMove(result));
 52 promise.resolve();
3853}
3954
4055} // namespace WebCore

Source/WebCore/Modules/paymentrequest/PaymentResponse.h

3232#include "PaymentComplete.h"
3333
3434namespace WebCore {
 35
 36class Document;
 37class PaymentRequest;
3538
3639class PaymentResponse final : public RefCounted<PaymentResponse> {
3740public:
 41 static Ref<PaymentResponse> create(PaymentRequest& request)
 42 {
 43 return adoptRef(*new PaymentResponse(request));
 44 }
 45
 46 ~PaymentResponse();
 47
3848 const String& requestId() const { return m_requestId; }
 49 void setRequestId(const String& requestId) { m_requestId = requestId; }
 50
3951 const String& methodName() const { return m_methodName; }
 52 void setMethodName(const String& methodName) { m_methodName = methodName; }
 53
4054 const JSC::Strong<JSC::JSObject>& details() const { return m_details; }
 55 void setDetails(JSC::Strong<JSC::JSObject>&& details) { m_details = WTFMove(details); }
 56
4157 PaymentAddress* shippingAddress() const { return m_shippingAddress.get(); }
 58 void setShippingAddress(PaymentAddress* shippingAddress) { m_shippingAddress = shippingAddress; }
 59
4260 const String& shippingOption() const { return m_shippingOption; }
 61 void setShippingOption(const String& shippingOption) { m_shippingOption = shippingOption; }
 62
4363 const String& payerName() const { return m_payerName; }
 64 void setPayerName(const String& payerName) { m_payerName = payerName; }
 65
4466 const String& payerEmail() const { return m_payerEmail; }
 67 void setPayerEmail(const String& payerEmail) { m_payerEmail = payerEmail; }
 68
4569 const String& payerPhone() const { return m_payerPhone; }
 70 void setPayerPhone(const String& payerPhone) { m_payerPhone = payerPhone; }
4671
4772 void complete(std::optional<PaymentComplete>&&, DOMPromiseDeferred<void>&&);
4873
4974private:
 75 explicit PaymentResponse(PaymentRequest&);
 76
 77 Ref<PaymentRequest> m_request;
5078 String m_requestId;
5179 String m_methodName;
5280 JSC::Strong<JSC::JSObject> m_details;

@@private:
5583 String m_payerName;
5684 String m_payerEmail;
5785 String m_payerPhone;
 86 bool m_completeCalled { false };
5887};
5988
6089} // namespace WebCore

Source/WebCore/WebCore.xcodeproj/project.pbxproj

40664066 A140618C1E2ECA0A0032B34E /* MockPreviewLoaderClient.h in Headers */ = {isa = PBXBuildFile; fileRef = A140618A1E2ECA0A0032B34E /* MockPreviewLoaderClient.h */; };
40674067 A14090FB1AA51E1D0091191A /* ContentFilterUnblockHandlerCocoa.mm in Sources */ = {isa = PBXBuildFile; fileRef = A14090FA1AA51E1D0091191A /* ContentFilterUnblockHandlerCocoa.mm */; };
40684068 A14090FD1AA51E480091191A /* ContentFilterUnblockHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = A14090FC1AA51E480091191A /* ContentFilterUnblockHandler.h */; settings = {ATTRIBUTES = (Private, ); }; };
 4069 A146D31A1F99BCF800D29196 /* JSMockPaymentCoordinator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A146D3191F99BCBB00D29196 /* JSMockPaymentCoordinator.cpp */; };
 4070 A146D31B1F99BCFB00D29196 /* JSMockPaymentCoordinator.h in Headers */ = {isa = PBXBuildFile; fileRef = A146D3181F99BCBA00D29196 /* JSMockPaymentCoordinator.h */; };
 4071 A146D3211F99CB1A00D29196 /* MockPaymentAddress.h in Headers */ = {isa = PBXBuildFile; fileRef = A146D31C1F99C9C200D29196 /* MockPaymentAddress.h */; };
 4072 A146D3221F99D0EC00D29196 /* JSMockPaymentAddress.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A146D3201F99CA3E00D29196 /* JSMockPaymentAddress.cpp */; };
 4073 A146D3231F99D0EF00D29196 /* JSMockPaymentAddress.h in Headers */ = {isa = PBXBuildFile; fileRef = A146D31F1F99CA3D00D29196 /* JSMockPaymentAddress.h */; };
 4074 A146D3251F99D69800D29196 /* MockPaymentContact.h in Headers */ = {isa = PBXBuildFile; fileRef = A146D3241F99D69800D29196 /* MockPaymentContact.h */; };
40694075 A14832B0187F618D00DA63A6 /* WAKAppKitStubs.h in Headers */ = {isa = PBXBuildFile; fileRef = A148328C187F508700DA63A6 /* WAKAppKitStubs.h */; settings = {ATTRIBUTES = (Private, ); }; };
40704076 A14832B1187F61E100DA63A6 /* WAKAppKitStubs.m in Sources */ = {isa = PBXBuildFile; fileRef = A148328D187F508700DA63A6 /* WAKAppKitStubs.m */; };
40714077 A14832B2187F61ED00DA63A6 /* WAKClipView.h in Headers */ = {isa = PBXBuildFile; fileRef = A148328E187F508700DA63A6 /* WAKClipView.h */; settings = {ATTRIBUTES = (Private, ); }; };

41004106 A149786E1ABAF33800CEF7E4 /* ContentFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A149786C1ABAF33800CEF7E4 /* ContentFilter.cpp */; };
41014107 A149786F1ABAF33800CEF7E4 /* ContentFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = A149786D1ABAF33800CEF7E4 /* ContentFilter.h */; };
41024108 A14978711ABAF3A500CEF7E4 /* PlatformContentFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = A14978701ABAF3A500CEF7E4 /* PlatformContentFilter.h */; };
 4109 A14BB0A01F9813B800605A35 /* MockPayment.h in Headers */ = {isa = PBXBuildFile; fileRef = A14BB09E1F9813B800605A35 /* MockPayment.h */; };
41034110 A15D75151E68F7C400A35FBC /* BlobCallback.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A15D75121E68F7B100A35FBC /* BlobCallback.cpp */; };
41044111 A15D75161E68F7C800A35FBC /* BlobCallback.h in Headers */ = {isa = PBXBuildFile; fileRef = A15D75131E68F7B100A35FBC /* BlobCallback.h */; };
41054112 A15D751B1E68F8A300A35FBC /* JSBlobCallback.h in Headers */ = {isa = PBXBuildFile; fileRef = A15D75181E68F83600A35FBC /* JSBlobCallback.h */; };

41454152 A1CC567B1F4614AD00A4555B /* JSPaymentResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = A1CC56641F46146700A4555B /* JSPaymentResponse.h */; };
41464153 A1CC567D1F4614B200A4555B /* JSPaymentShippingOption.h in Headers */ = {isa = PBXBuildFile; fileRef = A1CC56591F46145C00A4555B /* JSPaymentShippingOption.h */; };
41474154 A1CC567F1F4614B700A4555B /* JSPaymentShippingType.h in Headers */ = {isa = PBXBuildFile; fileRef = A1CC56501F46145300A4555B /* JSPaymentShippingType.h */; };
 4155 A1CFE0321F9E71290065C345 /* PaymentAddress.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A1CFE0311F9E71290065C345 /* PaymentAddress.cpp */; };
41484156 A1DE712D18612AC100734192 /* TouchEvents.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A1DE712B18612AC100734192 /* TouchEvents.cpp */; };
41494157 A1DF5A7F1F7EBD0B0058A477 /* ApplePayRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = A1DF5A7C1F7EBD0B0058A477 /* ApplePayRequest.h */; };
41504158 A1DF5A861F7EBDF20058A477 /* ApplePayMerchantCapability.h in Headers */ = {isa = PBXBuildFile; fileRef = A1DF5A831F7EBDF20058A477 /* ApplePayMerchantCapability.h */; };

1235512363 A140618A1E2ECA0A0032B34E /* MockPreviewLoaderClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MockPreviewLoaderClient.h; sourceTree = "<group>"; };
1235612364 A14090FA1AA51E1D0091191A /* ContentFilterUnblockHandlerCocoa.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ContentFilterUnblockHandlerCocoa.mm; sourceTree = "<group>"; };
1235712365 A14090FC1AA51E480091191A /* ContentFilterUnblockHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ContentFilterUnblockHandler.h; sourceTree = "<group>"; };
 12366 A146D3161F99B53D00D29196 /* MockPaymentCoordinator.idl */ = {isa = PBXFileReference; lastKnownFileType = text; path = MockPaymentCoordinator.idl; sourceTree = "<group>"; };
 12367 A146D3181F99BCBA00D29196 /* JSMockPaymentCoordinator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSMockPaymentCoordinator.h; sourceTree = "<group>"; };
 12368 A146D3191F99BCBB00D29196 /* JSMockPaymentCoordinator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSMockPaymentCoordinator.cpp; sourceTree = "<group>"; };
 12369 A146D31C1F99C9C200D29196 /* MockPaymentAddress.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MockPaymentAddress.h; sourceTree = "<group>"; };
 12370 A146D31E1F99C9C200D29196 /* MockPaymentAddress.idl */ = {isa = PBXFileReference; lastKnownFileType = text; path = MockPaymentAddress.idl; sourceTree = "<group>"; };
 12371 A146D31F1F99CA3D00D29196 /* JSMockPaymentAddress.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSMockPaymentAddress.h; sourceTree = "<group>"; };
 12372 A146D3201F99CA3E00D29196 /* JSMockPaymentAddress.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSMockPaymentAddress.cpp; sourceTree = "<group>"; };
 12373 A146D3241F99D69800D29196 /* MockPaymentContact.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MockPaymentContact.h; sourceTree = "<group>"; };
1235812374 A148328C187F508700DA63A6 /* WAKAppKitStubs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WAKAppKitStubs.h; sourceTree = "<group>"; };
1235912375 A148328D187F508700DA63A6 /* WAKAppKitStubs.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WAKAppKitStubs.m; sourceTree = "<group>"; };
1236012376 A148328E187F508700DA63A6 /* WAKClipView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WAKClipView.h; sourceTree = "<group>"; };

1238912405 A149786C1ABAF33800CEF7E4 /* ContentFilter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ContentFilter.cpp; sourceTree = "<group>"; };
1239012406 A149786D1ABAF33800CEF7E4 /* ContentFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ContentFilter.h; sourceTree = "<group>"; };
1239112407 A14978701ABAF3A500CEF7E4 /* PlatformContentFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PlatformContentFilter.h; sourceTree = "<group>"; };
 12408 A14BB09E1F9813B800605A35 /* MockPayment.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MockPayment.h; sourceTree = "<group>"; };
1239212409 A15D75121E68F7B100A35FBC /* BlobCallback.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BlobCallback.cpp; sourceTree = "<group>"; };
1239312410 A15D75131E68F7B100A35FBC /* BlobCallback.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BlobCallback.h; sourceTree = "<group>"; };
1239412411 A15D75141E68F7B100A35FBC /* BlobCallback.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = BlobCallback.idl; sourceTree = "<group>"; };

1245212469 A1CC56631F46146600A4555B /* JSPaymentCurrencyAmount.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSPaymentCurrencyAmount.h; sourceTree = "<group>"; };
1245312470 A1CC56641F46146700A4555B /* JSPaymentResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSPaymentResponse.h; sourceTree = "<group>"; };
1245412471 A1CC56651F46146800A4555B /* JSPaymentAddress.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSPaymentAddress.h; sourceTree = "<group>"; };
 12472 A1CFE0311F9E71290065C345 /* PaymentAddress.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = PaymentAddress.cpp; sourceTree = "<group>"; };
1245512473 A1DE712B18612AC100734192 /* TouchEvents.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TouchEvents.cpp; sourceTree = "<group>"; };
1245612474 A1DF5A7C1F7EBD0B0058A477 /* ApplePayRequest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ApplePayRequest.h; sourceTree = "<group>"; };
1245712475 A1DF5A7E1F7EBD0B0058A477 /* ApplePayRequest.idl */ = {isa = PBXFileReference; lastKnownFileType = text; path = ApplePayRequest.idl; sourceTree = "<group>"; };

1768917707 2D6F3E8C1C1ECB1C0061DBD4 /* MockPageOverlay.idl */,
1769017708 2DAAE32C19DCAF6000E002D2 /* MockPageOverlayClient.cpp */,
1769117709 2DAAE32D19DCAF6000E002D2 /* MockPageOverlayClient.h */,
 17710 A14BB09E1F9813B800605A35 /* MockPayment.h */,
 17711 A146D31C1F99C9C200D29196 /* MockPaymentAddress.h */,
 17712 A146D31E1F99C9C200D29196 /* MockPaymentAddress.idl */,
 17713 A146D3241F99D69800D29196 /* MockPaymentContact.h */,
1769217714 A1AFEDE51F8BFF6D0087013F /* MockPaymentCoordinator.cpp */,
1769317715 A1AFEDE41F8BFF6D0087013F /* MockPaymentCoordinator.h */,
 17716 A146D3161F99B53D00D29196 /* MockPaymentCoordinator.idl */,
1769417717 A14061891E2ECA0A0032B34E /* MockPreviewLoaderClient.cpp */,
1769517718 A140618A1E2ECA0A0032B34E /* MockPreviewLoaderClient.h */,
1769617719 EB081CD81696084400553730 /* TypeConversions.h */,

1772117744 A19AEA1E1AAA806E00B52B25 /* JSMockContentFilterSettings.h */,
1772217745 2D6F3E921C1F85550061DBD4 /* JSMockPageOverlay.cpp */,
1772317746 2D6F3E931C1F85550061DBD4 /* JSMockPageOverlay.h */,
 17747 A146D3201F99CA3E00D29196 /* JSMockPaymentAddress.cpp */,
 17748 A146D31F1F99CA3D00D29196 /* JSMockPaymentAddress.h */,
 17749 A146D3191F99BCBB00D29196 /* JSMockPaymentCoordinator.cpp */,
 17750 A146D3181F99BCBA00D29196 /* JSMockPaymentCoordinator.h */,
1772417751 EBF5121A1696496C0056BD25 /* JSTypeConversions.cpp */,
1772517752 EBF5121B1696496C0056BD25 /* JSTypeConversions.h */,
1772617753 );

2140821435 A1F76B0E1F44C0CF0014C318 /* paymentrequest */ = {
2140921436 isa = PBXGroup;
2141021437 children = (
 21438 A1CFE0311F9E71290065C345 /* PaymentAddress.cpp */,
2141121439 A1F76B401F44CF7F0014C318 /* PaymentAddress.h */,
2141221440 A1F76B421F44CF7F0014C318 /* PaymentAddress.idl */,
2141321441 A1F76B581F44D3B20014C318 /* PaymentComplete.h */,

2682026848 538EC9331F99B9F7004D22A8 /* JSMockCDMFactory.h in Headers */,
2682126849 A19AEA211AAA808600B52B25 /* JSMockContentFilterSettings.h in Headers */,
2682226850 538EC9341F99B9F7004D22A8 /* JSMockPageOverlay.h in Headers */,
 26851 A146D3231F99D0EF00D29196 /* JSMockPaymentAddress.h in Headers */,
 26852 A146D31B1F99BCFB00D29196 /* JSMockPaymentCoordinator.h in Headers */,
2682326853 EBF5121D1696496C0056BD25 /* JSTypeConversions.h in Headers */,
2682426854 CDC26B41160A8CCE0026757B /* LegacyMockCDM.h in Headers */,
2682526855 A1BF6B831AA96C7D00AF4A8A /* MockContentFilter.h in Headers */,

2682926859 4157EBFB1E3AB67F00AC9FE9 /* MockLibWebRTCPeerConnection.h in Headers */,
2683026860 2D6F3E911C1ECB2F0061DBD4 /* MockPageOverlay.h in Headers */,
2683126861 2D97F04819DD4140001EE9C3 /* MockPageOverlayClient.h in Headers */,
 26862 A14BB0A01F9813B800605A35 /* MockPayment.h in Headers */,
 26863 A146D3211F99CB1A00D29196 /* MockPaymentAddress.h in Headers */,
 26864 A146D3251F99D69800D29196 /* MockPaymentContact.h in Headers */,
2683226865 A1AFEDE61F8BFF6D0087013F /* MockPaymentCoordinator.h in Headers */,
2683326866 A140618C1E2ECA0A0032B34E /* MockPreviewLoaderClient.h in Headers */,
2683426867 AA5F3B8D16CC33D100455EB0 /* PlatformSpeechSynthesizerMock.h in Headers */,

2804328076 467302021C4EFE7800BCB357 /* IgnoreOpensDuringUnloadCountIncrementer.h in Headers */,
2804428077 B27535700B053814002CE64F /* Image.h in Headers */,
2804528078 55A336F91D821E3C0022C4C7 /* ImageBackingStore.h in Headers */,
 28079 31815A311F9A6C8F00FCBF89 /* ImageBitmap.h in Headers */,
2804628080 7C7903B31F86F95C00463A70 /* ImageBitmapRenderingContext.h in Headers */,
2804728081 B2A10B920B3818BD00099AA4 /* ImageBuffer.h in Headers */,
2804828082 22BD9F7F1353625C009BD102 /* ImageBufferData.h in Headers */,

3028730321 0F54DCE61881051D003EEDBB /* TextAutoSizing.h in Headers */,
3028830322 B2C3DA340D006C1D00EF6F26 /* TextBoundaries.h in Headers */,
3028930323 A7151BD812F1558F005A0F64 /* TextCheckerClient.h in Headers */,
30290  31815A311F9A6C8F00FCBF89 /* ImageBitmap.h in Headers */,
3029130324 A77D0012133B0AEB00D6658C /* TextChecking.h in Headers */,
3029230325 A7DBF8DE1276919C006B6008 /* TextCheckingHelper.h in Headers */,
3029330326 B2C3DA3A0D006C1D00EF6F26 /* TextCodec.h in Headers */,

3104431077 CDF4B7321E03D06000E235A2 /* JSMockCDMFactory.cpp in Sources */,
3104531078 A19AEA221AAA808A00B52B25 /* JSMockContentFilterSettings.cpp in Sources */,
3104631079 2D4150DE1C1F868C000A3BA2 /* JSMockPageOverlay.cpp in Sources */,
 31080 A146D3221F99D0EC00D29196 /* JSMockPaymentAddress.cpp in Sources */,
 31081 A146D31A1F99BCF800D29196 /* JSMockPaymentCoordinator.cpp in Sources */,
3104731082 EBF5121C1696496C0056BD25 /* JSTypeConversions.cpp in Sources */,
3104831083 CDC26B40160A8CC60026757B /* LegacyMockCDM.cpp in Sources */,
3104931084 CDF4B7311E03D00700E235A2 /* MockCDMFactory.cpp in Sources */,

3254832583 2D5002FB1B56D7990020AAF7 /* PathUtilities.cpp in Sources */,
3254932584 A8FA6E5E0E4CFDED00D5CF49 /* Pattern.cpp in Sources */,
3255032585 A80A38FE0E50CC8200A25EBC /* PatternCG.cpp in Sources */,
 32586 A1CFE0321F9E71290065C345 /* PaymentAddress.cpp in Sources */,
3255132587 1A8A646C1D19FF8700D0E00F /* PaymentCocoa.mm in Sources */,
3255232588 1A8A646D1D19FF8700D0E00F /* PaymentContactCocoa.mm in Sources */,
3255332589 1A58E86D1D19E42D00C0EA73 /* PaymentCoordinator.cpp in Sources */,

3278832824 514C76500CE9234E007EF3CD /* ResourceErrorMac.mm in Sources */,
3278932825 514C76780CE923A1007EF3CD /* ResourceHandle.cpp in Sources */,
3279032826 7EE6846C12D26E3800E79415 /* ResourceHandleCFNet.cpp in Sources */,
32791  532042021F9A9F1000B81B2A /* UserAgentScriptsData.cpp in Sources */,
3279232827 26FAE4CC1852E3A5004C8C46 /* ResourceHandleCFURLConnectionDelegate.cpp in Sources */,
3279332828 26C15CF61857E15D00F15C03 /* ResourceHandleCFURLConnectionDelegateWithOperationQueue.cpp in Sources */,
3279432829 E1BA003116FB92AC00BA7A35 /* ResourceHandleClient.cpp in Sources */,

3351133546 5D5975B71963637B00D00878 /* UserAgent.mm in Sources */,
3351233547 26255F0018878DFF0006E1FD /* UserAgentIOS.mm in Sources */,
3351333548 26255F0418878E110006E1FD /* UserAgentMac.mm in Sources */,
 33549 532042021F9A9F1000B81B2A /* UserAgentScriptsData.cpp in Sources */,
3351433550 1AE79D42188DB61F002239C2 /* UserContentController.cpp in Sources */,
3351533551 7C3F01C21C8E5AC200ADD962 /* UserContentProvider.cpp in Sources */,
3351633552 BCACF3BC1072921A00C0C8A3 /* UserContentURLPattern.cpp in Sources */,

Source/WebCore/testing/Internals.cpp

@@Internals::Internals(Document& document)
513513 setConsoleMessageListener(nullptr);
514514
515515#if ENABLE(APPLE_PAY)
516  if (auto frame = document.frame())
517  frame->mainFrame().setPaymentCoordinator(std::make_unique<PaymentCoordinator>(*new MockPaymentCoordinator(frame->mainFrame())));
 516 auto* frame = document.frame();
 517 if (frame && frame->isMainFrame()) {
 518 m_mockPaymentCoordinator = new MockPaymentCoordinator(frame->mainFrame());
 519 frame->mainFrame().setPaymentCoordinator(std::make_unique<PaymentCoordinator>(*m_mockPaymentCoordinator));
 520 }
518521#endif
519522}
520523

@@Ref<ExtendableEvent> Internals::createTrustedExtendableEvent()
42454248}
42464249#endif
42474250
 4251#if ENABLE(APPLE_PAY)
 4252MockPaymentCoordinator& Internals::mockPaymentCoordinator() const
 4253{
 4254 return *m_mockPaymentCoordinator;
 4255}
 4256#endif
 4257
42484258} // namespace WebCore

Source/WebCore/testing/Internals.h

@@class MemoryInfo;
7272class MockCDMFactory;
7373class MockContentFilterSettings;
7474class MockPageOverlay;
 75class MockPaymentCoordinator;
7576class NodeList;
7677class Page;
7778class Range;

@@public:
616617#endif
617618
618619 bool hasServiceWorkerRegisteredForOrigin(const String&);
 620
 621#if ENABLE(APPLE_PAY)
 622 MockPaymentCoordinator& mockPaymentCoordinator() const;
 623#endif
619624
620625private:
621626 explicit Internals(Document&);

@@private:
638643
639644 std::unique_ptr<InspectorStubFrontend> m_inspectorFrontend;
640645 RefPtr<CacheStorageConnection> m_cacheStorageConnection;
 646
 647#if ENABLE(APPLE_PAY)
 648 MockPaymentCoordinator* m_mockPaymentCoordinator { nullptr };
 649#endif
641650};
642651
643652} // namespace WebCore

Source/WebCore/testing/Internals.idl

@@enum EventThrottlingBehavior {
560560 [Conditional=SERVICE_WORKER] ExtendableEvent createTrustedExtendableEvent();
561561
562562 boolean hasServiceWorkerRegisteredForOrigin(DOMString origin);
 563
 564 [Conditional=APPLE_PAY] readonly attribute MockPaymentCoordinator mockPaymentCoordinator;
563565};

Source/WebCore/testing/MockPayment.h

 1/*
 2 * Copyright (C) 2017 Apple Inc. All rights reserved.
 3 *
 4 * Redistribution and use in source and binary forms, with or without
 5 * modification, are permitted provided that the following conditions
 6 * are met:
 7 * 1. Redistributions of source code must retain the above copyright
 8 * notice, this list of conditions and the following disclaimer.
 9 * 2. Redistributions in binary form must reproduce the above copyright
 10 * notice, this list of conditions and the following disclaimer in the
 11 * documentation and/or other materials provided with the distribution.
 12 *
 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 23 * THE POSSIBILITY OF SUCH DAMAGE.
 24 */
 25
 26#pragma once
 27
 28#if ENABLE(APPLE_PAY)
 29
 30#include "ApplePayPayment.h"
 31#include "Payment.h"
 32
 33namespace WebCore {
 34
 35class MockPayment final : public Payment {
 36public:
 37 explicit MockPayment(ApplePayPayment&& applePayPayment)
 38 : m_applePayPayment { WTFMove(applePayPayment) }
 39 {
 40 }
 41
 42 ApplePayPayment toApplePayPayment() const final { return m_applePayPayment; }
 43
 44private:
 45 ApplePayPayment m_applePayPayment;
 46};
 47
 48} // namespace WebCore
 49
 50#endif // ENABLE(APPLE_PAY)

Source/WebCore/testing/MockPaymentAddress.h

 1/*
 2 * Copyright (C) 2017 Apple Inc. All rights reserved.
 3 *
 4 * Redistribution and use in source and binary forms, with or without
 5 * modification, are permitted provided that the following conditions
 6 * are met:
 7 * 1. Redistributions of source code must retain the above copyright
 8 * notice, this list of conditions and the following disclaimer.
 9 * 2. Redistributions in binary form must reproduce the above copyright
 10 * notice, this list of conditions and the following disclaimer in the
 11 * documentation and/or other materials provided with the distribution.
 12 *
 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 23 * THE POSSIBILITY OF SUCH DAMAGE.
 24 */
 25
 26#pragma once
 27
 28#if ENABLE(APPLE_PAY)
 29
 30#include "ApplePayPaymentContact.h"
 31
 32namespace WebCore {
 33
 34struct MockPaymentAddress : ApplePayPaymentContact {
 35};
 36
 37} // namespace WebCore
 38
 39#endif // ENABLE(APPLE_PAY)

Source/WebCore/testing/MockPaymentAddress.idl

 1/*
 2 * Copyright (C) 2017 Apple Inc. All rights reserved.
 3 *
 4 * Redistribution and use in source and binary forms, with or without
 5 * modification, are permitted provided that the following conditions
 6 * are met:
 7 * 1. Redistributions of source code must retain the above copyright
 8 * notice, this list of conditions and the following disclaimer.
 9 * 2. Redistributions in binary form must reproduce the above copyright
 10 * notice, this list of conditions and the following disclaimer in the
 11 * documentation and/or other materials provided with the distribution.
 12 *
 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 23 * THE POSSIBILITY OF SUCH DAMAGE.
 24 */
 25
 26[
 27 Conditional=APPLE_PAY
 28] dictionary MockPaymentAddress {
 29 DOMString countryCode;
 30 FrozenArray<DOMString> addressLines;
 31 DOMString administrativeArea;
 32 DOMString locality;
 33 DOMString subLocality;
 34 DOMString postalCode;
 35 DOMString localizedName;
 36 DOMString phoneNumber;
 37 DOMString emailAddress;
 38};

Source/WebCore/testing/MockPaymentContact.h

 1/*
 2 * Copyright (C) 2017 Apple Inc. All rights reserved.
 3 *
 4 * Redistribution and use in source and binary forms, with or without
 5 * modification, are permitted provided that the following conditions
 6 * are met:
 7 * 1. Redistributions of source code must retain the above copyright
 8 * notice, this list of conditions and the following disclaimer.
 9 * 2. Redistributions in binary form must reproduce the above copyright
 10 * notice, this list of conditions and the following disclaimer in the
 11 * documentation and/or other materials provided with the distribution.
 12 *
 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 23 * THE POSSIBILITY OF SUCH DAMAGE.
 24 */
 25
 26#pragma once
 27
 28#if ENABLE(APPLE_PAY)
 29
 30#include "ApplePayPaymentContact.h"
 31#include "PaymentContact.h"
 32
 33namespace WebCore {
 34
 35class MockPaymentContact final : public PaymentContact {
 36public:
 37 explicit MockPaymentContact(ApplePayPaymentContact&& applePayPaymentContact)
 38 : m_applePayPaymentContact { WTFMove(applePayPaymentContact) }
 39 {
 40 }
 41
 42 ApplePayPaymentContact toApplePayPaymentContact() const final { return m_applePayPaymentContact; }
 43
 44private:
 45 ApplePayPaymentContact m_applePayPaymentContact;
 46};
 47
 48} // namespace WebCore
 49
 50#endif // ENABLE(APPLE_PAY)

Source/WebCore/testing/MockPaymentCoordinator.cpp

2929#if ENABLE(APPLE_PAY)
3030
3131#include "MainFrame.h"
 32#include "MockPayment.h"
 33#include "MockPaymentContact.h"
3234#include "PaymentCoordinator.h"
3335#include "URL.h"
3436#include <wtf/RunLoop.h>

@@bool MockPaymentCoordinator::canMakePayments()
5860 return true;
5961}
6062
61 void MockPaymentCoordinator::canMakePaymentsWithActiveCard(const String&, const String&, WTF::Function<void(bool)>&& completionHandler)
 63void MockPaymentCoordinator::canMakePaymentsWithActiveCard(const String&, const String&, Function<void(bool)>&& completionHandler)
6264{
6365 RunLoop::main().dispatch([completionHandler = WTFMove(completionHandler)]() {
6466 completionHandler(true);
6567 });
6668}
6769
68 void MockPaymentCoordinator::openPaymentSetup(const String&, const String&, WTF::Function<void(bool)>&& completionHandler)
 70void MockPaymentCoordinator::openPaymentSetup(const String&, const String&, Function<void(bool)>&& completionHandler)
6971{
7072 RunLoop::main().dispatch([completionHandler = WTFMove(completionHandler)]() {
7173 completionHandler(true);
7274 });
7375}
7476
 77static uint64_t showCount;
 78static uint64_t hideCount;
 79
 80static void dispatchIfShowing(Function<void()>&& function)
 81{
 82 ASSERT(showCount > hideCount);
 83 RunLoop::main().dispatch([currentShowCount = showCount, function = WTFMove(function)]() {
 84 if (showCount > hideCount && showCount == currentShowCount)
 85 function();
 86 });
 87}
 88
7589bool MockPaymentCoordinator::showPaymentUI(const URL&, const Vector<URL>&, const ApplePaySessionPaymentRequest&)
7690{
77  RunLoop::main().dispatch([mainFrame = makeRef(m_mainFrame)]() {
 91 ASSERT(showCount == hideCount);
 92 ++showCount;
 93 dispatchIfShowing([mainFrame = makeRef(m_mainFrame)]() {
7894 mainFrame->paymentCoordinator().validateMerchant({ URL(), ASCIILiteral("https://webkit.org/") });
7995 });
8096 return true;
8197}
8298
 99void MockPaymentCoordinator::completeMerchantValidation(const PaymentMerchantSession&)
 100{
 101 dispatchIfShowing([mainFrame = makeRef(m_mainFrame), shippingAddress = m_shippingAddress]() {
 102 ApplePayPaymentContact contact = shippingAddress;
 103 mainFrame->paymentCoordinator().didSelectShippingContact(MockPaymentContact { WTFMove(contact) });
 104
 105 ApplePayPayment payment;
 106 payment.shippingContact = shippingAddress;
 107 mainFrame->paymentCoordinator().didAuthorizePayment(MockPayment { WTFMove(payment) });
 108 });
 109}
 110
 111void MockPaymentCoordinator::completePaymentSession(std::optional<PaymentAuthorizationResult>&&)
 112{
 113 ++hideCount;
 114 ASSERT(showCount == hideCount);
 115}
 116
 117void MockPaymentCoordinator::abortPaymentSession()
 118{
 119 ++hideCount;
 120 ASSERT(showCount == hideCount);
 121}
 122
 123void MockPaymentCoordinator::cancelPaymentSession()
 124{
 125 ++hideCount;
 126 ASSERT(showCount == hideCount);
 127}
 128
83129void MockPaymentCoordinator::paymentCoordinatorDestroyed()
84130{
 131 ASSERT(showCount == hideCount);
85132 delete this;
86133}
87134

Source/WebCore/testing/MockPaymentCoordinator.h

2727
2828#if ENABLE(APPLE_PAY)
2929
 30#include "MockPaymentAddress.h"
3031#include "PaymentCoordinatorClient.h"
3132
3233namespace WebCore {

@@class MockPaymentCoordinator final : public PaymentCoordinatorClient {
3738public:
3839 explicit MockPaymentCoordinator(MainFrame&);
3940
 41 void setShippingAddress(MockPaymentAddress&& shippingAddress) { m_shippingAddress = WTFMove(shippingAddress); }
 42
 43 void ref() const { }
 44 void deref() const { }
 45
4046private:
4147 bool supportsVersion(unsigned) final;
4248 bool canMakePayments() final;
4349 void canMakePaymentsWithActiveCard(const String&, const String&, WTF::Function<void(bool)>&&);
4450 void openPaymentSetup(const String&, const String&, WTF::Function<void(bool)>&&);
4551 bool showPaymentUI(const URL&, const Vector<URL>&, const ApplePaySessionPaymentRequest&) final;
46  void completeMerchantValidation(const PaymentMerchantSession&) final { }
 52 void completeMerchantValidation(const PaymentMerchantSession&) final;
4753 void completeShippingMethodSelection(std::optional<ShippingMethodUpdate>&&) final { }
4854 void completeShippingContactSelection(std::optional<ShippingContactUpdate>&&) final { }
4955 void completePaymentMethodSelection(std::optional<PaymentMethodUpdate>&&) final { }
50  void completePaymentSession(std::optional<PaymentAuthorizationResult>&&) final { }
51  void abortPaymentSession() final { }
52  void cancelPaymentSession() final { }
 56 void completePaymentSession(std::optional<PaymentAuthorizationResult>&&) final;
 57 void abortPaymentSession() final;
 58 void cancelPaymentSession() final;
5359 void paymentCoordinatorDestroyed() final;
5460
5561 MainFrame& m_mainFrame;
 62 MockPaymentAddress m_shippingAddress;
5663};
5764
5865} // namespace WebCore

Source/WebCore/testing/MockPaymentCoordinator.idl

 1/*
 2 * Copyright (C) 2017 Apple Inc. All rights reserved.
 3 *
 4 * Redistribution and use in source and binary forms, with or without
 5 * modification, are permitted provided that the following conditions
 6 * are met:
 7 * 1. Redistributions of source code must retain the above copyright
 8 * notice, this list of conditions and the following disclaimer.
 9 * 2. Redistributions in binary form must reproduce the above copyright
 10 * notice, this list of conditions and the following disclaimer in the
 11 * documentation and/or other materials provided with the distribution.
 12 *
 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 23 * THE POSSIBILITY OF SUCH DAMAGE.
 24 */
 25
 26[
 27 Conditional=APPLE_PAY,
 28 NoInterfaceObject,
 29] interface MockPaymentCoordinator {
 30 void setShippingAddress(MockPaymentAddress shippingAddress);
 31};

LayoutTests/ChangeLog

 12017-10-20 Andy Estes <aestes@apple.com>
 2
 3 [Payment Request] Resolve PaymentRequest.show()'s accept promise when a payment is authorized
 4 https://bugs.webkit.org/show_bug.cgi?id=178609
 5
 6 Reviewed by Alex Christensen.
 7
 8 * http/tests/paymentrequest/payment-address-attributes-and-toJSON-method.https-expected.txt: Added.
 9 * http/tests/paymentrequest/payment-address-attributes-and-toJSON-method.https.html: Added.
 10 * http/tests/paymentrequest/payment-response-complete-method.https-expected.txt: Added.
 11 * http/tests/paymentrequest/payment-response-complete-method.https.html: Added.
 12 * http/tests/paymentrequest/payment-response-methodName-attribute.https-expected.txt: Added.
 13 * http/tests/paymentrequest/payment-response-methodName-attribute.https.html: Added.
 14 * http/tests/paymentrequest/payment-response-payerEmail-attribute.https-expected.txt: Added.
 15 * http/tests/paymentrequest/payment-response-payerEmail-attribute.https.html: Added.
 16 * http/tests/paymentrequest/payment-response-payerName-attribute.https-expected.txt: Added.
 17 * http/tests/paymentrequest/payment-response-payerName-attribute.https.html: Added.
 18 * http/tests/paymentrequest/payment-response-payerPhone-attribute.https-expected.txt: Added.
 19 * http/tests/paymentrequest/payment-response-payerPhone-attribute.https.html: Added.
 20 * http/tests/paymentrequest/resources/helpers.js: Added.
 21 (test):
 22 (async.getPaymentResponse):
 23 (async.getPaymentRequestResponse):
 24 (async.runTest):
 25
1262017-10-20 Matt Lewis <jlewis3@apple.com>
227
328 Marked plugins/js-from-destroy.html as flaky.

LayoutTests/http/tests/paymentrequest/payment-address-attributes-and-toJSON-method.https-expected.txt

 1If the requestShipping member is true, then shippingAddress's PaymentAddress must match the expected values.
 2
 3PASS Can construct a payment request (smoke test).
 4PASS If the requestShipping member is true, then shippingAddress's PaymentAddress must match the expected values.
 5

LayoutTests/http/tests/paymentrequest/payment-address-attributes-and-toJSON-method.https.html

 1<!doctype html>
 2<meta charset="utf8">
 3<link rel="help" href="https://www.w3.org/TR/payment-request/#paymentaddress-interface">
 4<title>
 5 PaymentResponse.prototype.shippingAddress
 6</title>
 7<script src="/resources/testharness.js"></script>
 8<script src="/resources/testharnessreport.js"></script>
 9<script src="resources/helpers.js"></script>
 10<script>
 11const options = { requestShipping: true };
 12function runTest(button, expected = {}) {
 13 button.disabled = true;
 14 promise_test(async () => {
 15 const { response } = await getPaymentRequestResponse(options);
 16 await response.complete();
 17 assert_idl_attribute(response, "shippingAddress");
 18 const { shippingAddress: addr } = response;
 19 assert_true(
 20 addr instanceof PaymentAddress,
 21 "Expect instance of PaymentAddress"
 22 );
 23 // An [ISO3166] alpha-2 code. The canonical form is upper case.
 24 const { country } = addr;
 25 assert_equals(country.length, 2, "Expected length is 2");
 26 assert_true(/^[A-Z]{2}$/.test(country), "Canonical form is upper case");
 27 assert_true(
 28 addr.addressLine instanceof Array,
 29 "Expected addressLine to be an array"
 30 );
 31 assert_throws(
 32 new TypeError(),
 33 () => {
 34 addr.addressLine.push("this must throw");
 35 },
 36 "Array must be frozen"
 37 );
 38 for (let [attr, expectedValue] of Object.entries(expected)) {
 39 assert_idl_attribute(addr, attr);
 40 const msg = `Expected paymentAddress.${attr} to equal ${expectedValue}.`;
 41 //.toString() flattens array addressLine,
 42 //.toLowerCase() because case can't be enforced for some attributes
 43 const actualValue = addr[attr].toString().toLowerCase();
 44 expectedValue = expectedValue.toString().toLowerCase();
 45 assert_equals(actualValue, expectedValue, msg);
 46 }
 47 // Check toJSON result
 48 for (let [prop, jsonValue] of Object.entries(addr.toJSON())) {
 49 const actualValue = jsonValue.toString().toLowerCase();
 50 const expectedValue = expected[prop].toString().toLowerCase();
 51 const msg = `Expected JSON ${prop} to be ${expectedValue}`;
 52 assert_equals(actualValue, expectedValue, msg);
 53 }
 54 }, button.textContent.trim());
 55 done();
 56}
 57</script>
 58<ol>
 59 <li>
 60 <button id="button">
 61 If the requestShipping member is true, then shippingAddress's PaymentAddress must match the expected values.
 62 </button>
 63 </li>
 64</ol>
 65<script>
 66 const address = {
 67 countryCode: 'AF',
 68 addressLines: ['1 wpt street'],
 69 locality: 'Kabul',
 70 postalCode: '1001',
 71 localizedName: 'web platform test',
 72 phoneNumber: '+93555555555',
 73 };
 74 internals.mockPaymentCoordinator.setShippingAddress(address);
 75
 76 const expectedAddress = {
 77 country: address.countryCode,
 78 addressLine: address.addressLines,
 79 region: '',
 80 city: address.locality,
 81 dependentLocality: '',
 82 postalCode: address.postalCode,
 83 sortingCode: '',
 84 languageCode: '',
 85 organization: '',
 86 recipient: address.localizedName,
 87 phone: address.phoneNumber,
 88 };
 89 runTest(document.getElementById("button"), expectedAddress);
 90</script>

LayoutTests/http/tests/paymentrequest/payment-response-complete-method.https-expected.txt

 1✅ If the value of the internal slot [[completeCalled]] is true, reject promise with an "InvalidStateError" DOMException.
 2✅ Passing no argument defaults to "unknown", eventually closing the sheet and doesn't throw.
 3✅ Passing "success" eventually closes the sheet and doesn't throw.
 4✅ Passing "fail" eventually closes the sheet and doesn't throw.
 5
 6PASS Can construct a payment request (smoke test).
 7PASS If the value of the internal slot [[completeCalled]] is true,
 8 reject promise with an "InvalidStateError" DOMException.
 9PASS Passing no argument defaults to "unknown",
 10 eventually closing the sheet and doesn't throw.
 11PASS Passing "success" eventually closes the sheet and doesn't throw.
 12PASS Passing "fail" eventually closes the sheet and doesn't throw.
 13

LayoutTests/http/tests/paymentrequest/payment-response-complete-method.https.html

 1<!doctype html>
 2<meta charset="utf8">
 3<link rel="help" href="https://w3c.github.io/payment-request/#dom-paymentresponse-complete()">
 4<title>
 5 PaymentResponse.prototype.complete() method
 6</title>
 7<script src="/resources/testharness.js"></script>
 8<script src="/resources/testharnessreport.js"></script>
 9<script src="resources/helpers.js"></script>
 10<script>
 11async function runTest({ completeWith: result }, button) {
 12 button.disabled = true;
 13 const { response, request } = await getPaymentRequestResponse();
 14 promise_test(async () => {
 15 try {
 16 // We .complete() as normal, using the passed test value
 17 const promise = response.complete(result);
 18 assert_true(promise instanceof Promise, "returns a promise");
 19 const returnedValue = await promise;
 20 assert_equals(
 21 returnedValue,
 22 undefined,
 23 "Returned value must always be undefined"
 24 );
 25 // We now call .complete() again, to force an exception
 26 // because [[completeCalled]] is true.
 27 try {
 28 await response.complete(result);
 29 assert_unreached("Expected InvalidStateError to be thrown");
 30 } catch (err) {
 31 assert_equals(
 32 err.code,
 33 DOMException.INVALID_STATE_ERR,
 34 "Must throw an InvalidStateError"
 35 );
 36 }
 37 button.innerHTML = `✅ ${button.textContent}`;
 38 } catch (err) {
 39 button.innerHTML = `❌ ${button.textContent}`;
 40 assert_unreached("Unexpected exception: " + err.message);
 41 }
 42 }, button.textContent.trim());
 43}
 44</script>
 45<ol>
 46 <li>
 47 <button id="button1">
 48 If the value of the internal slot [[completeCalled]] is true,
 49 reject promise with an "InvalidStateError" DOMException.
 50 </button>
 51 </li>
 52 <li>
 53 <button id="button2">
 54 Passing no argument defaults to "unknown",
 55 eventually closing the sheet and doesn't throw.
 56 </button>
 57 </li>
 58 <li>
 59 <button id="button3">
 60 Passing "success" eventually closes the sheet and doesn't throw.
 61 </button>
 62 </li>
 63 <li>
 64 <button id="button4">
 65 Passing "fail" eventually closes the sheet and doesn't throw.
 66 </button>
 67 </li>
 68</ol>
 69<script>
 70 async function runTests()
 71 {
 72 await runTest({completeWith: "success"}, document.getElementById("button1"));
 73 await runTest({completeWith: "unknown"}, document.getElementById("button2"));
 74 await runTest({completeWith: "success"}, document.getElementById("button3"));
 75 await runTest({completeWith: "fail"}, document.getElementById("button4"));
 76 done();
 77 }
 78 runTests();
 79</script>

LayoutTests/http/tests/paymentrequest/payment-response-methodName-attribute.https-expected.txt

 1Expect the payment method identifier to be 'https://apple.com/apple-pay'.
 2
 3PASS Can construct a payment request (smoke test).
 4PASS Expect the payment method identifier to be 'https://apple.com/apple-pay'.
 5

LayoutTests/http/tests/paymentrequest/payment-response-methodName-attribute.https.html

 1<!doctype html>
 2<meta charset="utf8">
 3<link rel="help" href="https://w3c.github.io/payment-request/#dom-paymentresponse-methodname">
 4<title>
 5 PaymentResponse.prototype.methodName attribute
 6</title>
 7<script src="/resources/testharness.js"></script>
 8<script src="/resources/testharnessreport.js"></script>
 9<script src="resources/helpers.js"></script>
 10<ol>
 11 <li>
 12 <button id="button">
 13 Expect the payment method identifier to be 'https://apple.com/apple-pay'.
 14 </button>
 15 </li>
 16</ol>
 17<script>
 18 runTest(document.getElementById("button"), {}, { methodName: 'https://apple.com/apple-pay' }).then(done);
 19</script>

LayoutTests/http/tests/paymentrequest/payment-response-payerEmail-attribute.https-expected.txt

 1payerEmail attribute is null when options undefined.
 2payerEmail attribute is null when requestPayerEmail is undefined.
 3payerEmail attribute is null when requestPayerEmail is false.
 4payerEmail attribute is 'wpt@w3.org' when requestPayerEmail is true.
 5payerEmail attribute is 'wpt@w3.org' when requestPayerEmail is truthy.
 6
 7PASS Can construct a payment request (smoke test).
 8PASS payerEmail attribute is null when options undefined.
 9PASS payerEmail attribute is null when requestPayerEmail is undefined.
 10PASS payerEmail attribute is null when requestPayerEmail is false.
 11PASS payerEmail attribute is 'wpt@w3.org' when requestPayerEmail is true.
 12PASS payerEmail attribute is 'wpt@w3.org' when requestPayerEmail is truthy.
 13

LayoutTests/http/tests/paymentrequest/payment-response-payerEmail-attribute.https.html

 1<!doctype html>
 2<meta charset="utf8">
 3<link rel="help" href="https://w3c.github.io/payment-request/#dom-paymentresponse-payeremail">
 4<title>
 5 PaymentResponse.prototype.payerEmail attribute
 6</title>
 7<script src="/resources/testharness.js"></script>
 8<script src="/resources/testharnessreport.js"></script>
 9<script src="resources/helpers.js"></script>
 10<ol>
 11 <li>
 12 <button id="button1">
 13 payerEmail attribute is null when options undefined.
 14 </button>
 15 </li>
 16 <li>
 17 <button id="button2">
 18 payerEmail attribute is null when requestPayerEmail is undefined.
 19 </button>
 20 </li>
 21 <li>
 22 <button id="button3">
 23 payerEmail attribute is null when requestPayerEmail is false.
 24 </button>
 25 </li>
 26 <li>
 27 <button id="button4">
 28 payerEmail attribute is 'wpt@w3.org' when requestPayerEmail is true.
 29 </button>
 30 </li>
 31 <li>
 32 <button id="button5">
 33 payerEmail attribute is 'wpt@w3.org' when requestPayerEmail is truthy.
 34 </button>
 35 </li>
 36</ol>
 37<script>
 38 internals.mockPaymentCoordinator.setShippingAddress({ emailAddress: 'wpt@w3.org' });
 39
 40 async function runTests()
 41 {
 42 await runTest(document.getElementById("button1"), undefined, { payerEmail: null });
 43 await runTest(document.getElementById("button2"), { requestPayerEmail: undefined }, { payerEmail: null });
 44 await runTest(document.getElementById("button3"), { requestPayerEmail: false }, { payerEmail: null });
 45 await runTest(document.getElementById("button4"), { requestPayerEmail: true }, { payerEmail: 'wpt@w3.org' });
 46 await runTest(document.getElementById("button5"), { requestPayerEmail: 'yep' }, { payerEmail: 'wpt@w3.org' });
 47 done();
 48 }
 49 runTests();
 50</script>

LayoutTests/http/tests/paymentrequest/payment-response-payerName-attribute.https-expected.txt

 1payerName attribute is null when option is undefined.
 2payerName attribute is null when requestPayerName is undefined.
 3payerName attribute is null when requestPayerName is false.
 4payerName attribute is 'web platform test' when requestPayerName is true.
 5payerName attribute is 'web platform test' when requestPayerName is truthy.
 6
 7PASS Can construct a payment request (smoke test).
 8PASS payerName attribute is null when option is undefined.
 9PASS payerName attribute is null when requestPayerName is undefined.
 10PASS payerName attribute is null when requestPayerName is false.
 11PASS payerName attribute is 'web platform test' when requestPayerName is true.
 12PASS payerName attribute is 'web platform test' when requestPayerName is truthy.
 13

LayoutTests/http/tests/paymentrequest/payment-response-payerName-attribute.https.html

 1<!doctype html>
 2<meta charset="utf8">
 3<link rel="help" href="https://w3c.github.io/payment-request/#dom-paymentresponse-payername">
 4<title>
 5 PaymentResponse.prototype.payerName attribute
 6</title>
 7<script src="/resources/testharness.js"></script>
 8<script src="/resources/testharnessreport.js"></script>
 9<script src="resources/helpers.js"></script>
 10<ol>
 11 <li>
 12 <button id="button1">
 13 payerName attribute is null when option is undefined.
 14 </button>
 15 </li>
 16 <li>
 17 <button id="button2">
 18 payerName attribute is null when requestPayerName is undefined.
 19 </button>
 20 </li>
 21 <li>
 22 <button id="button3">
 23 payerName attribute is null when requestPayerName is false.
 24 </button>
 25 </li>
 26 <li>
 27 <button id="button4">
 28 payerName attribute is 'web platform test' when requestPayerName is true.
 29 </button>
 30 </li>
 31 <li>
 32 <button id="button5">
 33 payerName attribute is 'web platform test' when requestPayerName is truthy.
 34 </button>
 35 </li>
 36</ol>
 37<script>
 38 internals.mockPaymentCoordinator.setShippingAddress({ localizedName: 'web platform test' });
 39
 40 async function runTests()
 41 {
 42 await runTest(document.getElementById("button1"), undefined, { payerName: null });
 43 await runTest(document.getElementById("button2"), { requestPayerName: undefined }, { payerName: null });
 44 await runTest(document.getElementById("button3"), { requestPayerName: false }, { payerName: null });
 45 await runTest(document.getElementById("button4"), { requestPayerName: true }, { payerName: 'web platform test' });
 46 await runTest(document.getElementById("button5"), { requestPayerName: 'yep' }, { payerName: 'web platform test' });
 47 done();
 48 }
 49 runTests();
 50</script>

LayoutTests/http/tests/paymentrequest/payment-response-payerPhone-attribute.https-expected.txt

 1payerPhone attribute is null when options is undefined.
 2payerPhone attribute is null when requestPayerPhone is undefined.
 3payerPhone attribute is null when requestPayerPhone is false.
 4payerPhone attribute is '+12345678910' when requestPayerPhone is true.
 5payerPhone attribute is '+12345678910' when requestPayerPhone is truthy.
 6
 7PASS Can construct a payment request (smoke test).
 8PASS payerPhone attribute is null when options is undefined.
 9PASS payerPhone attribute is null when requestPayerPhone is undefined.
 10PASS payerPhone attribute is null when requestPayerPhone is false.
 11PASS payerPhone attribute is '+12345678910' when requestPayerPhone is true.
 12PASS payerPhone attribute is '+12345678910' when requestPayerPhone is truthy.
 13

LayoutTests/http/tests/paymentrequest/payment-response-payerPhone-attribute.https.html

 1<!doctype html>
 2<meta charset="utf8">
 3<link rel="help" href="https://w3c.github.io/payment-request/#dom-paymentresponse-payerphone">
 4<title>
 5 PaymentResponse.prototype.payerPhone attribute
 6</title>
 7<script src="/resources/testharness.js"></script>
 8<script src="/resources/testharnessreport.js"></script>
 9<script src="resources/helpers.js"></script>
 10<ol>
 11 <li>
 12 <button id="button1">
 13 payerPhone attribute is null when options is undefined.
 14 </button>
 15 </li>
 16 <li>
 17 <button id="button2">
 18 payerPhone attribute is null when requestPayerPhone is undefined.
 19 </button>
 20 </li>
 21 <li>
 22 <button id="button3">
 23 payerPhone attribute is null when requestPayerPhone is false.
 24 </button>
 25 </li>
 26 <li>
 27 <button id="button4">
 28 payerPhone attribute is '+12345678910' when requestPayerPhone is true.
 29 </button>
 30 </li>
 31 <li>
 32 <button id="button5">
 33 payerPhone attribute is '+12345678910' when requestPayerPhone is truthy.
 34 </button>
 35 </li>
 36</ol>
 37<script>
 38 internals.mockPaymentCoordinator.setShippingAddress({ phoneNumber: '+12345678910' });
 39
 40 async function runTests()
 41 {
 42 await runTest(document.getElementById("button1"), undefined, { payerPhone: null });
 43 await runTest(document.getElementById("button2"), { requestPayerPhone: undefined }, { payerPhone: null });
 44 await runTest(document.getElementById("button3"), { requestPayerPhone: false }, { payerPhone: null });
 45 await runTest(document.getElementById("button4"), { requestPayerPhone: true }, { payerPhone: '+12345678910' });
 46 await runTest(document.getElementById("button5"), { requestPayerPhone: 'yep' }, { payerPhone: '+12345678910' });
 47 done();
 48 }
 49 runTests();
 50</script>

LayoutTests/http/tests/paymentrequest/resources/helpers.js

 1setup({ explicit_done: true, explicit_timeout: true });
 2
 3const validMethod = Object.freeze({
 4 supportedMethods: "https://apple.com/apple-pay",
 5 data: {
 6 version: 2,
 7 merchantIdentifier: '',
 8 merchantCapabilities: ['supports3DS'],
 9 supportedNetworks: ['visa', 'masterCard'],
 10 countryCode: 'US',
 11 },
 12});
 13
 14const validMethods = Object.freeze([validMethod]);
 15
 16const validAmount = Object.freeze({
 17 currency: "USD",
 18 value: "1.00",
 19});
 20
 21const validTotal = Object.freeze({
 22 label: "Valid total",
 23 amount: validAmount,
 24});
 25const validDetails = {
 26 total: validTotal,
 27};
 28
 29test(() => {
 30 try {
 31 new PaymentRequest(validMethods, validDetails);
 32 } catch (err) {
 33 done();
 34 throw err;
 35 }
 36}, "Can construct a payment request (smoke test).");
 37
 38/**
 39 * Pops up a payment sheet, allowing options to be
 40 * passed in if particular values are needed.
 41 *
 42 * @param PaymentOptions options
 43 */
 44async function getPaymentResponse(options, id) {
 45 const { response } = getPaymentRequestResponse(options, id);
 46 return response;
 47}
 48
 49/**
 50 * Creates a payment request and response pair.
 51 * It also shows the payment sheet.
 52 *
 53 * @param {PaymentOptions?} options
 54 * @param {String?} id
 55 */
 56async function getPaymentRequestResponse(options, id) {
 57 const methods = [{
 58 supportedMethods: "https://apple.com/apple-pay",
 59 data: {
 60 version: 2,
 61 merchantIdentifier: '',
 62 merchantCapabilities: ['supports3DS'],
 63 supportedNetworks: ['visa', 'masterCard'],
 64 countryCode: 'US',
 65 },
 66 }];
 67 const details = {
 68 id,
 69 total: {
 70 label: "Total due",
 71 amount: { currency: "USD", value: "1.0" },
 72 },
 73 shippingOptions: [
 74 {
 75 id: "fail1",
 76 label: "Fail option 1",
 77 amount: { currency: "USD", value: "5.00" },
 78 selected: false,
 79 },
 80 {
 81 id: "pass",
 82 label: "Pass option",
 83 amount: { currency: "USD", value: "5.00" },
 84 selected: true,
 85 },
 86 {
 87 id: "fail2",
 88 label: "Fail option 2",
 89 amount: { currency: "USD", value: "5.00" },
 90 selected: false,
 91 },
 92 ],
 93 };
 94 const request = new PaymentRequest(methods, details, options);
 95 request.onshippingaddresschange = ev => ev.updateWith(details);
 96 request.onshippingoptionchange = ev => ev.updateWith(details);
 97 request.onapplepayvalidatemerchant = ev => ev.complete({});
 98 const response = await request.show();
 99 return { request, response };
 100}
 101
 102/**
 103 * Runs a manual test for payment
 104 *
 105 * @param {HTMLButtonElement} button The HTML button.
 106 * @param {PaymentOptions?} options.
 107 * @param {Object} expected What property values are expected to pass the test.
 108 * @param {String?} id And id for the request/response pair.
 109 */
 110async function runTest(button, options, expected = {}, id = undefined) {
 111 button.disabled = true;
 112 const { request, response } = await getPaymentRequestResponse(options, id);
 113 await response.complete();
 114 test(() => {
 115 assert_idl_attribute(
 116 response,
 117 "requestId",
 118 "Expected requestId to be an IDL attribute."
 119 );
 120 assert_equals(response.requestId, request.id, `Expected ids to match`);
 121 for (const [attribute, value] of Object.entries(expected)) {
 122 assert_idl_attribute(
 123 response,
 124 attribute,
 125 `Expected ${attribute} to be an IDL attribute.`
 126 );
 127 assert_equals(
 128 response[attribute],
 129 value,
 130 `Expected response ${attribute} attribute to be ${value}`
 131 );
 132 }
 133 assert_idl_attribute(response, "details");
 134 assert_equals(typeof response.details, "object", "Expected an object");
 135 // Testing that this does not throw:
 136 response.toJSON();
 137 if (options && options.requestShipping) {
 138 assert_equals(
 139 response.shippingOption,
 140 "pass",
 141 "request.shippingOption must be 'pass'"
 142 );
 143 } else {
 144 assert_equals(
 145 request.shippingOption,
 146 null,
 147 "If requestShipping is falsy, request.shippingOption must be null"
 148 );
 149 assert_equals(
 150 response.shippingOption,
 151 null,
 152 "request.shippingOption must be null"
 153 );
 154 }
 155 }, button.textContent.trim());
 156}