diff --git a/payment-request/META.yml b/payment-request/META.yml index 1dbe3e5d7edbe4..3985039a4291da 100644 --- a/payment-request/META.yml +++ b/payment-request/META.yml @@ -1,7 +1,5 @@ spec: https://w3c.github.io/payment-request/ suggested_reviewers: - marcoscaceres - - rsolomakhin - - zouhir - romandev - - aestes + - stephenmcgruer diff --git a/payment-request/payment-is-showing.https.html b/payment-request/payment-is-showing.https.html index a30029458f5f2f..c97473cc6f122b 100644 --- a/payment-request/payment-is-showing.https.html +++ b/payment-request/payment-is-showing.https.html @@ -91,6 +91,7 @@ // 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 + await test_driver.bless("payment request show()"); const rejectedPromise = request2.show(); await promise_rejects_dom( t, diff --git a/payment-request/payment-response/rejects_if_not_active-manual.https.html b/payment-request/payment-response/rejects_if_not_active-manual.https.html index 6f2e9e95d41d9f..af33bc0f74fdc7 100644 --- a/payment-request/payment-response/rejects_if_not_active-manual.https.html +++ b/payment-request/payment-response/rejects_if_not_active-manual.https.html @@ -52,7 +52,7 @@ }); } -function methodNotFullyActive(button, method, ...args) { +function methodNotFullyActive(button, methodName, ...args) { const text = button.textContent.trim(); promise_test(async t => { const iframe = document.createElement("iframe"); @@ -74,9 +74,9 @@ const promise = response[methodName](...args); await promise_rejects_dom( t, - "AbortError", + "InvalidStateError", promise, - "Inactive document, so must throw AbortError" + "Inactive document, so must throw InvalidStateError" ); // We are done, so clean up. iframe.remove(); @@ -111,7 +111,7 @@ t, "AbortError", promise, - "Inactive document, so must throw AbortError" + "Document became inactive, so must throw AbortError" ); // We are done, so clean up. iframe.remove(); diff --git a/payment-request/rejects_if_not_active.https.html b/payment-request/rejects_if_not_active.https.html index 32feccb2655f34..0233aca9d053b6 100644 --- a/payment-request/rejects_if_not_active.https.html +++ b/payment-request/rejects_if_not_active.https.html @@ -1,7 +1,8 @@ -PaymentRequest show() rejects if doc is not fully active +PaymentRequest methods reject if doc is not fully active + @@ -72,16 +73,18 @@ // So, call .show(), and make sure it rejects appropriately. await promise_rejects_dom( t, - "AbortError", + "InvalidStateError", frameDOMException1, request1.show(), - "Inactive document, so must throw AbortError" + "Inactive document, so must throw InvalidStateError" ); // request2 has an active document tho, so confirm it's working as expected: // Get transient activation await test_driver.bless("payment 2", () => {}, iframe.contentWindow); request2.show(); await request2.abort(); + // Need another bless() because the previous one was consumed by show() + await test_driver.bless("payment 3", () => {}, iframe.contentWindow); await promise_rejects_dom( t, "InvalidStateError", @@ -132,11 +135,93 @@ // So, call request.show() and make sure it rejects appropriately. await promise_rejects_dom( t, - "AbortError", + "InvalidStateError", innerIframeDOMException, showPromise, - "Active, but not fully active, so must throw AbortError" + "Active, but not fully active, so must throw InvalidStateError" ); }, "PaymentRequest.show() aborts if the document is active, but not fully active."); + + promise_test(async (t) => { + const iframe = document.createElement("iframe"); + iframe.allow = "payment"; + document.body.appendChild(iframe); + t.add_cleanup(() => { + iframe.remove(); + }); + // We first go to page1.html, grab a PaymentRequest instance. + const request1 = await getLoadedPaymentRequest( + iframe, + "./resources/page1.html" + ); + // Save the DOMException of page1.html before navigating away. + const frameDOMException1 = iframe.contentWindow.DOMException; + + // We navigate the iframe again, putting request1's document into an non-fully active state. + const request2 = await getLoadedPaymentRequest( + iframe, + "./resources/page2.html" + ); + + // Now, request1's relevant global object's document is no longer active. + // So, call .canMakePayment(), and make sure it rejects appropriately. + await promise_rejects_dom( + t, + "InvalidStateError", + frameDOMException1, + request1.canMakePayment(), + "Inactive document, so must throw InvalidStateError" + ); + // request2 has an active document, so confirm it's working as expected: + const result = await request2.canMakePayment(); + assert_true(typeof result === "boolean", "canMakePayment() should return a boolean"); + }, "PaymentRequest.canMakePayment() rejects if the document is not active."); + + promise_test(async (t) => { + // We nest two iframes and wait for them to load. + const outerIframe = document.createElement("iframe"); + outerIframe.allow = "payment"; + document.body.appendChild(outerIframe); + t.add_cleanup(() => { + outerIframe.remove(); + }); + // Load the outer iframe (we don't care about the awaited request) + await getLoadedPaymentRequest(outerIframe, "./resources/page1.html"); + + // Now we create the inner iframe + const innerIframe = outerIframe.contentDocument.createElement("iframe"); + innerIframe.allow = "payment"; + + // nest them + outerIframe.contentDocument.body.appendChild(innerIframe); + + // load innerIframe, and get the PaymentRequest instance + const request = await getLoadedPaymentRequest( + innerIframe, + "./resources/page2.html" + ); + // Save DOMException from innerIframe before navigating away. + const innerIframeDOMException = innerIframe.contentWindow.DOMException; + + // Navigate the outer iframe to a new location. + // Wait for the load event to fire. + await new Promise((resolve) => { + outerIframe.addEventListener("load", resolve); + outerIframe.src = "./resources/page2.html"; + }); + + const canMakePaymentPromise = request.canMakePayment(); + // Now, request's relevant global object's document is still active + // (it is the active document of the inner iframe), but is not fully active + // (since the parent of the inner iframe is itself no longer active). + // So, call request.canMakePayment() and make sure it rejects appropriately. + await promise_rejects_dom( + t, + "InvalidStateError", + innerIframeDOMException, + canMakePaymentPromise, + "Active, but not fully active, so must throw InvalidStateError" + ); + }, "PaymentRequest.canMakePayment() rejects if the document is active, but not fully active.");