WebKit Bugzilla
Attachment 372960 Details for
Bug 199239
: [Payment Request] Set state to Closed when show() is called during an active session
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-199239-20190626160009.patch (text/plain), 14.35 KB, created by
Andy Estes
on 2019-06-26 16:00:09 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Andy Estes
Created:
2019-06-26 16:00:09 PDT
Size:
14.35 KB
patch
obsolete
>Subversion Revision: 246723 >diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog >index 94ec8a3a5e244c03bee9b326e46c720505267593..b05660606e5c50ca26ff836faa59de38be02d880 100644 >--- a/Source/WebCore/ChangeLog >+++ b/Source/WebCore/ChangeLog >@@ -1,3 +1,20 @@ >+2019-06-26 Andy Estes <aestes@apple.com> >+ >+ [Payment Request] Set state to Closed when show() is called during an active session >+ https://bugs.webkit.org/show_bug.cgi?id=199239 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ According to step 7 of https://w3c.github.io/payment-request/#show-method (as of 26 June >+ 2019), when another payment request is showing, calling show() should set the [[state]] >+ internal slot to Closed in addition to rejecting the show promise with an AbortError. WebKit >+ was only doing the latter. Let's do both. >+ >+ Test: http/tests/paymentrequest/payment-is-showing.https.html >+ >+ * Modules/paymentrequest/PaymentRequest.cpp: >+ (WebCore::PaymentRequest::show): >+ > 2019-06-23 Simon Fraser <simon.fraser@apple.com> > > Add OverflowScrollProxyNodes to the scrolling tree >diff --git a/Source/WebCore/Modules/paymentrequest/PaymentRequest.cpp b/Source/WebCore/Modules/paymentrequest/PaymentRequest.cpp >index d2ef7a61ed510b06a32c052fc70903655b39e00a..0774fc6e15b6f9853c2d0b3e148ba5cfc371c834 100644 >--- a/Source/WebCore/Modules/paymentrequest/PaymentRequest.cpp >+++ b/Source/WebCore/Modules/paymentrequest/PaymentRequest.cpp >@@ -404,6 +404,7 @@ void PaymentRequest::show(Document& document, RefPtr<DOMPromise>&& detailsPromis > > if (PaymentHandler::hasActiveSession(document)) { > promise.reject(Exception { AbortError }); >+ m_state = State::Closed; > return; > } > >diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog >index 7a71643345bec0f9efe5295ce781fd768a8a9c3c..aca1c3e36c66a69bb558ae57a9dd48008a063caf 100644 >--- a/LayoutTests/ChangeLog >+++ b/LayoutTests/ChangeLog >@@ -1,3 +1,17 @@ >+2019-06-26 Andy Estes <aestes@apple.com> >+ >+ [Payment Request] Set state to Closed when show() is called during an active session >+ https://bugs.webkit.org/show_bug.cgi?id=199239 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Copied from web-platform-tests/payment-request/payment-is-showing.https.html and modified to >+ use UIHelper instead of test_driver.bless. >+ >+ * http/tests/paymentrequest/payment-is-showing.https-expected.txt: Added. >+ * http/tests/paymentrequest/payment-is-showing.https.html: Added. >+ * http/tests/paymentrequest/resources/blank.html: Added. >+ > 2019-06-23 Antoine Quint <graouts@apple.com> > > [Pointer Events WPT] Unflake imported/w3c/web-platform-tests/pointerevents/pointerevent_mouse_pointercapture_in_frame.html >diff --git a/LayoutTests/http/tests/paymentrequest/payment-is-showing.https-expected.txt b/LayoutTests/http/tests/paymentrequest/payment-is-showing.https-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..8ece644db1fca13beff454e117d93db66299b155 >--- /dev/null >+++ b/LayoutTests/http/tests/paymentrequest/payment-is-showing.https-expected.txt >@@ -0,0 +1,8 @@ >+ >+PASS The top browsing context can only show one payment sheet at a time. >+PASS If an iframe shows a payment request, the top-level browsing context can't also show one. >+PASS An iframe cannot show a payment request if the top-level window is already showing one. >+PASS Given multiple nested browsing contexts, and window calls show() first, other nested browsing contexts can't show a request. >+PASS Given multiple nested browsing contexts, and an iframe calls show() first, other nested browsing contexts can't show a request. >+PASS Navigating an iframe as a nested browsing context sets 'payment request is showing boolean' to false. >+ >diff --git a/LayoutTests/http/tests/paymentrequest/payment-is-showing.https.html b/LayoutTests/http/tests/paymentrequest/payment-is-showing.https.html >new file mode 100644 >index 0000000000000000000000000000000000000000..2e9a24c8002d388a8c3c8ff9f1ad86bdc809c690 >--- /dev/null >+++ b/LayoutTests/http/tests/paymentrequest/payment-is-showing.https.html >@@ -0,0 +1,290 @@ >+<!DOCTYPE html> <meta charset="utf-8" /> >+<title>Test for PaymentRequest.show(optional promise) method</title> >+<link >+ rel="help" >+ href="https://w3c.github.io/browser-payment-api/#dfn-payment-request-is-showing" >+/> >+<script src="/js-test-resources/ui-helper.js"></script> >+<script src="/resources/payment-request.js"></script> >+<script src="/resources/testharness.js"></script> >+<script src="/resources/testharnessreport.js"></script> >+<body> >+ <script> >+ 'use strict'; >+ const applePayMethod = { >+ supportedMethods: 'https://apple.com/apple-pay', >+ data: { >+ version: 3, >+ merchantIdentifier: 'merchant.com.example', >+ countryCode: 'US', >+ merchantCapabilities: ['supports3DS'], >+ supportedNetworks: ['visa'], >+ }, >+ }; >+ const methods = [{supportedMethods: 'basic-card'}, applePayMethod]; >+ const details = { >+ total: { >+ label: 'Total', >+ amount: { >+ currency: 'USD', >+ value: '1.00', >+ }, >+ }, >+ }; >+ >+ /** >+ * Attaches an iframe to window.document. >+ * >+ * @param {String} src Optional resource URL to load. >+ * @returns {Promise} Resolves when the src loads. >+ */ >+ async function attachIframe(src = 'resources/blank.html') { >+ const iframe = document.createElement('iframe'); >+ iframe.allowPaymentRequest = true; >+ iframe.src = src; >+ document.body.appendChild(iframe); >+ await new Promise(resolve => { >+ iframe.addEventListener('load', resolve, {once: true}); >+ }); >+ return iframe; >+ } >+ >+ /** >+ * Creates a popup window. The caller must be triggered with a user gesture. >+ * >+ * @param {String} src Optional resource URL to load. >+ * @returns {Promise} Resolves when the src loads. >+ */ >+ async function loadPopupInsideUserGesture(src = 'resources/blank.html') { >+ const popupWindow = window.open(src, '', 'width=400,height=400'); >+ await new Promise(resolve => { >+ popupWindow.addEventListener('load', resolve, {once: true}); >+ }); >+ popupWindow.focus(); >+ return popupWindow; >+ } >+ >+ promise_test(async t => { >+ const request1 = new PaymentRequest(methods, details); >+ const request2 = new PaymentRequest(methods, details); >+ >+ // Sets the "payment-relevant browsing context's payment request is >+ // showing boolean" to true and then try to show a second payment sheet in >+ // the same window. The second show() should reject. >+ const [showPromise1, showPromise2] = await activateThen( >+ async () => { >+ return [request1.show(), request2.show()]; >+ } >+ ); >+ await promise_rejects( >+ t, >+ 'AbortError', >+ showPromise2, >+ 'Attempting to show a second payment request must reject.', >+ ); >+ >+ await request1.abort(); >+ await promise_rejects( >+ t, >+ 'AbortError', >+ showPromise1, >+ 'request1 was aborted via .abort()', >+ ); >+ >+ // Finally, request2 should have been "closed", so trying to show >+ // it will again result in promise rejected with an InvalidStateError. >+ // See: https://github.com/w3c/payment-request/pull/821 >+ const [rejectedPromise] = await activateThen(async () => { return [request2.show()] }); >+ await promise_rejects( >+ t, >+ 'InvalidStateError', >+ rejectedPromise, >+ 'Attempting to show a second payment request must reject.', >+ ); >+ // Finally, we confirm that request2's returned promises are unique. >+ assert_not_equals( >+ showPromise2, >+ rejectedPromise, >+ 'Returned Promises be unique', >+ ); >+ }, 'The top browsing context can only show one payment sheet at a time.'); >+ >+ promise_test(async t => { >+ const iframe = await attachIframe(); >+ const iframeWindow = iframe.contentWindow; >+ >+ // Payment requests >+ const iframeRequest = new iframeWindow.PaymentRequest(methods, details); >+ const windowRequest = new window.PaymentRequest(methods, details); >+ >+ // Let's get some blessed showPromises >+ const [iframeShowPromise, windowShowPromise] = await activateThen( >+ async () => { >+ // iframe sets "is showing boolean", ignore the returned promise. >+ // The top level window now tries to show() the payment request. >+ return [iframeRequest.show(), windowRequest.show()]; >+ } >+ ); >+ >+ await promise_rejects( >+ t, >+ 'AbortError', >+ windowShowPromise, >+ 'iframe is already showing a payment request.', >+ ); >+ >+ // Cleanup >+ await iframeRequest.abort(); >+ await promise_rejects( >+ t, >+ 'AbortError', >+ iframeShowPromise, >+ 'abort() was called'); >+ iframe.remove(); >+ }, "If an iframe shows a payment request, the top-level browsing context can't also show one."); >+ >+ promise_test(async t => { >+ const iframe = await attachIframe(); >+ const iframeWindow = iframe.contentWindow; >+ >+ // Payment requests >+ const iframeRequest = new iframeWindow.PaymentRequest(methods, details); >+ const windowRequest = new window.PaymentRequest(methods, details); >+ >+ // We first show a payment request via the the top level browsing context, >+ // windowRequest.show() sets "is showing boolean" to true. Then we try to >+ // show a payment request in the iframe, which should reject. >+ const [windowShowPromise, iframeShowPromise] = await activateThen( >+ async () => { >+ return [windowRequest.show(), iframeRequest.show()]; >+ } >+ ); >+ >+ await promise_rejects( >+ t, >+ 'AbortError', >+ iframeShowPromise, >+ 'The top window is already showing a payment request.', >+ ); >+ >+ // Cleanup >+ await windowRequest.abort(); >+ await promise_rejects( >+ t, >+ 'AbortError', >+ windowShowPromise, >+ 'abort() was called'); >+ iframe.remove(); >+ }, 'An iframe cannot show a payment request if the top-level window is already showing one.'); >+ >+ promise_test(async t => { >+ const iframe = await attachIframe(); >+ const iframeWindow = iframe.contentWindow; >+ >+ // Create requests >+ const windowRequest = new window.PaymentRequest(methods, details); >+ const iframeRequest = new iframeWindow.PaymentRequest(methods, details); >+ >+ // Get the showPromise for each browsing context. Doing this in a separate >+ // test_driver.bless() is important because the user gesture brings >+ // |window| to the foreground, so that the payment sheet can show. >+ const [ >+ windowShowPromise, >+ iframeShowPromise, >+ ] = await activateThen( >+ async () => { >+ return [ >+ windowRequest.show(), >+ iframeRequest.show(), >+ ]; >+ } >+ ); >+ >+ await promise_rejects( >+ t, >+ 'AbortError', >+ iframeShowPromise, >+ 'Expected iframeShowPromise to reject, request is already showing.', >+ ); >+ >+ await windowRequest.abort(); >+ await promise_rejects( >+ t, >+ 'AbortError', >+ windowShowPromise, >+ 'abort() was called'); >+ iframe.remove(); >+ }, "Given multiple nested browsing contexts, and window calls show() first, other nested browsing contexts can't show a request."); >+ >+ promise_test(async t => { >+ const iframe = await attachIframe(); >+ const iframeWindow = iframe.contentWindow; >+ >+ // Create requests >+ const windowRequest = new window.PaymentRequest(methods, details); >+ const iframeRequest = new iframeWindow.PaymentRequest(methods, details); >+ >+ // Get the showPromise for each browsing context. Doing this in a separate >+ // test_driver.bless() is important because the user gesture brings >+ // |window| to the foreground, so that the payment sheet can show. >+ const [ >+ iframeShowPromise, >+ windowShowPromise, >+ ] = await activateThen( >+ async () => { >+ return [ >+ iframeRequest.show(), >+ windowRequest.show(), >+ ]; >+ } >+ ); >+ >+ // windowShowPromise and iframeRequest will both reject >+ await promise_rejects( >+ t, >+ 'AbortError', >+ windowShowPromise, >+ 'Expected windowShowPromise to reject, the popup is showing a payment request.', >+ ); >+ >+ await iframeRequest.abort(); >+ await promise_rejects( >+ t, >+ 'AbortError', >+ iframeShowPromise, >+ 'abort() was called'); >+ iframe.remove(); >+ }, "Given multiple nested browsing contexts, and an iframe calls show() first, other nested browsing contexts can't show a request."); >+ >+ promise_test(async t => { >+ const iframe = await attachIframe(); >+ const iframeWindow = iframe.contentWindow; >+ const iframeRequest = new iframeWindow.PaymentRequest(methods, details); >+ const [iframeShowPromise] = await activateThen( >+ async () => { return [iframeRequest.show()] } >+ ); >+ >+ // We navigate away, causing the payment sheet to close >+ // and the request is showing boolean to become false. >+ iframe.src = 'resources/blank.html?abc=123'; >+ await new Promise(resolve => (iframe.onload = resolve)); >+ await promise_rejects( >+ t, >+ 'AbortError', >+ iframeShowPromise, >+ 'Navigating iframe away must cause the iframeShowPromise to reject.', >+ ); >+ iframe.remove(); >+ >+ // Now we should be ok to spin up a new payment request >+ const request = new window.PaymentRequest(methods, details); >+ const [showPromise] = await activateThen(async () => { return [request.show()] }); >+ await request.abort(); >+ await promise_rejects( >+ t, >+ 'AbortError', >+ showPromise, >+ 'abort() was called'); >+ }, "Navigating an iframe as a nested browsing context sets 'payment request is showing boolean' to false."); >+ </script> >+</body> >diff --git a/LayoutTests/http/tests/paymentrequest/resources/blank.html b/LayoutTests/http/tests/paymentrequest/resources/blank.html >new file mode 100644 >index 0000000000000000000000000000000000000000..7852a427e861a9be3c9068deb306b67ad909843f >--- /dev/null >+++ b/LayoutTests/http/tests/paymentrequest/resources/blank.html >@@ -0,0 +1 @@ >+<!DOCTYPE html> <meta charset="utf-8" />
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 199239
: 372960