rejects_if_not_active.https.html (5080B)
1 <!DOCTYPE html> 2 <meta charset="utf-8" /> 3 <title>PaymentRequest show() rejects if doc is not fully active</title> 4 <link rel="help" href="https://w3c.github.io/payment-request/#show-method" /> 5 <script src="/resources/testharness.js"></script> 6 <script src="/resources/testharnessreport.js"></script> 7 <script src="/resources/testdriver.js"></script> 8 <script src="/resources/testdriver-vendor.js"></script> 9 <body> 10 <script> 11 const applePay = Object.freeze({ 12 supportedMethods: "https://apple.com/apple-pay", 13 data: { 14 version: 3, 15 merchantIdentifier: "merchant.com.example", 16 countryCode: "US", 17 merchantCapabilities: ["supports3DS"], 18 supportedNetworks: ["visa"], 19 }, 20 }); 21 const validMethod = Object.freeze({ 22 supportedMethods: "basic-card", 23 }); 24 const validMethods = Object.freeze([validMethod, applePay]); 25 26 const validDetails = Object.freeze({ 27 total: { 28 label: "Total due", 29 amount: { 30 currency: "USD", 31 value: "5.00", 32 }, 33 }, 34 }); 35 36 async function getLoadedPaymentRequest(iframe, url) { 37 await new Promise((resolve) => { 38 iframe.addEventListener("load", resolve, { once: true }); 39 iframe.src = url; 40 }); 41 return new iframe.contentWindow.PaymentRequest( 42 validMethods, 43 validDetails 44 ); 45 } 46 47 promise_test(async (t) => { 48 const iframe = document.createElement("iframe"); 49 iframe.allow = "payment"; 50 document.body.appendChild(iframe); 51 t.add_cleanup(() => { 52 iframe.remove(); 53 }); 54 // We first got to page1.html, grab a PaymentRequest instance. 55 const request1 = await getLoadedPaymentRequest( 56 iframe, 57 "./resources/page1.html" 58 ); 59 // Save the DOMException of page1.html before navigating away. 60 const frameDOMException1 = iframe.contentWindow.DOMException; 61 62 // Get transient activation 63 await test_driver.bless("payment 1", () => {}, iframe.contentWindow); 64 65 // We navigate the iframe again, putting request1's document into an non-fully active state. 66 const request2 = await getLoadedPaymentRequest( 67 iframe, 68 "./resources/page2.html" 69 ); 70 71 // Now, request1's relevant global object's document is no longer active. 72 // So, call .show(), and make sure it rejects appropriately. 73 await promise_rejects_dom( 74 t, 75 "AbortError", 76 frameDOMException1, 77 request1.show(), 78 "Inactive document, so must throw AbortError" 79 ); 80 // request2 has an active document tho, so confirm it's working as expected: 81 // Get transient activation 82 await test_driver.bless("payment 2", () => {}, iframe.contentWindow); 83 request2.show(); 84 await request2.abort(); 85 await promise_rejects_dom( 86 t, 87 "InvalidStateError", 88 iframe.contentWindow.DOMException, 89 request2.show(), 90 "Abort already called, so InvalidStateError" 91 ); 92 }, "PaymentRequest.show() aborts if the document is not active."); 93 94 promise_test(async (t) => { 95 // We nest two iframes and wait for them to load. 96 const outerIframe = document.createElement("iframe"); 97 outerIframe.allow = "payment"; 98 document.body.appendChild(outerIframe); 99 t.add_cleanup(() => { 100 outerIframe.remove(); 101 }); 102 // Load the outer iframe (we don't care about the awaited request) 103 await getLoadedPaymentRequest(outerIframe, "./resources/page1.html"); 104 105 // Now we create the inner iframe 106 const innerIframe = outerIframe.contentDocument.createElement("iframe"); 107 innerIframe.allow = "payment"; 108 109 // nest them 110 outerIframe.contentDocument.body.appendChild(innerIframe); 111 112 // load innerIframe, and get the PaymentRequest instance 113 const request = await getLoadedPaymentRequest( 114 innerIframe, 115 "./resources/page2.html" 116 ); 117 // Save DOMException from innerIframe before navigating away. 118 const innerIframeDOMException = innerIframe.contentWindow.DOMException; 119 120 // Navigate the outer iframe to a new location. 121 // Wait for the load event to fire. 122 await new Promise((resolve) => { 123 outerIframe.addEventListener("load", resolve); 124 outerIframe.src = "./resources/page2.html"; 125 }); 126 127 await test_driver.bless("", () => {}, innerIframe.contentWindow); 128 const showPromise = request.show(); 129 // Now, request's relevant global object's document is still active 130 // (it is the active document of the inner iframe), but is not fully active 131 // (since the parent of the inner iframe is itself no longer active). 132 // So, call request.show() and make sure it rejects appropriately. 133 await promise_rejects_dom( 134 t, 135 "AbortError", 136 innerIframeDOMException, 137 showPromise, 138 "Active, but not fully active, so must throw AbortError" 139 ); 140 }, "PaymentRequest.show() aborts if the document is active, but not fully active."); 141 </script> 142 </body>