updateWith-method-abort-update-manual.https.html (8290B)
1 <!doctype html> 2 <meta charset="utf8"> 3 <link rel="help" href="https://w3c.github.io/payment-request/#dfn-abort-the-update"> 4 <title> 5 updateWith() method - "abort the update" 6 </title> 7 <script src="/resources/testharness.js"></script> 8 <script src="/resources/testharnessreport.js"></script> 9 <script> 10 setup({ explicit_done: true, explicit_timeout: true }); 11 12 // PaymentMethod 13 const validMethod = Object.freeze({ 14 supportedMethods: "valid-but-wont-ever-match", 15 }); 16 17 const validMethodBasicCard = Object.freeze({ 18 supportedMethods: "basic-card", 19 }); 20 21 const applePay = Object.freeze({ 22 supportedMethods: "https://apple.com/apple-pay", 23 data: { 24 version: 3, 25 merchantIdentifier: "merchant.com.example", 26 countryCode: "US", 27 merchantCapabilities: ["supports3DS"], 28 supportedNetworks: ["visa"], 29 } 30 }); 31 32 // Methods 33 const validMethods = Object.freeze([validMethodBasicCard, validMethod, applePay]); 34 35 // Amounts 36 const validAmount = Object.freeze({ 37 currency: "USD", 38 value: "1.00", 39 }); 40 41 const invalidAmount = Object.freeze({ 42 currency: "¡INVALID!", 43 value: "A1.0", 44 }); 45 46 const negativeAmount = Object.freeze({ 47 currency: "USD", 48 value: "-1.00", 49 }); 50 51 // Totals 52 const validTotal = Object.freeze({ 53 label: "Valid Total", 54 amount: validAmount, 55 }); 56 57 const invalidTotal = Object.freeze({ 58 label: "Invalid Total", 59 amount: invalidAmount, 60 }); 61 62 const invalidNegativeTotal = Object.freeze({ 63 label: "Invalid negative total", 64 amount: negativeAmount, 65 }); 66 67 // PaymentDetailsInit 68 const validDetails = Object.freeze({ 69 total: validTotal, 70 }); 71 72 const invalidDetailsNegativeTotal = Object.freeze({ 73 total: invalidNegativeTotal, 74 }); 75 76 // PaymentOptions 77 const validOptions = Object.freeze({ 78 requestShipping: true, 79 }); 80 81 // PaymentItem 82 const validPaymentItem = Object.freeze({ 83 amount: validAmount, 84 label: "Valid payment item", 85 }); 86 87 const invalidPaymentItem = Object.freeze({ 88 amount: invalidAmount, 89 label: "Invalid payment item", 90 }); 91 92 // PaymentItem 93 const validPaymentItems = Object.freeze([validPaymentItem]); 94 const invalidPaymentItems = Object.freeze([invalidPaymentItem]); 95 96 // PaymentShippingOption 97 const invalidShippingOption = Object.freeze({ 98 id: "abc", 99 label: "Invalid shipping option", 100 amount: invalidAmount, 101 selected: true, 102 }); 103 104 // PaymentShippingOptions 105 const validShippingOption = Object.freeze({ 106 id: "abc", 107 label: "valid shipping option", 108 amount: validAmount, 109 }); 110 111 const validShippingOptions = Object.freeze([validShippingOption]); 112 const invalidShippingOptions = Object.freeze([invalidShippingOption]); 113 114 // PaymentDetailsModifier 115 const validModifier = Object.freeze({ 116 additionalDisplayItems: validPaymentItems, 117 supportedMethods: "valid-but-wont-ever-match", 118 total: validTotal, 119 }); 120 121 const modifierWithInvalidDisplayItems = Object.freeze({ 122 additionalDisplayItems: invalidPaymentItems, 123 supportedMethods: "basic-card", 124 total: validTotal, 125 }); 126 127 const modifierWithValidDisplayItems = Object.freeze({ 128 additionalDisplayItems: validPaymentItems, 129 supportedMethods: "basic-card", 130 total: validTotal, 131 }); 132 133 const modifierWithInvalidTotal = Object.freeze({ 134 additionalDisplayItems: validPaymentItems, 135 supportedMethods: "basic-card", 136 total: invalidTotal, 137 }); 138 139 const recursiveData = {}; 140 recursiveData.foo = recursiveData; 141 Object.freeze(recursiveData); 142 143 const modifierWithRecursiveData = Object.freeze({ 144 supportedMethods: "basic-card", 145 total: validTotal, 146 data: recursiveData, 147 }); 148 149 function testBadUpdate(button, badDetails, expectedError, errorCode) { 150 button.disabled = true; 151 promise_test(async t => { 152 const request = new PaymentRequest( 153 validMethods, 154 validDetails, 155 validOptions 156 ); 157 request.onshippingaddresschange = event => { 158 event.updateWith(badDetails); 159 }; 160 // First we check the bad update. 161 const acceptPromise = request.show(); 162 let test_func; 163 if (typeof expectedError == "function") { 164 test_func = promise_rejects_js; 165 } else { 166 test_func = promise_rejects_dom; 167 } 168 await test_func( 169 t, 170 expectedError, 171 acceptPromise, 172 "badDetails must cause acceptPromise to reject with expectedError" 173 ); 174 // The request [[state]] is now "closed", so let's check for InvalidStateError 175 await promise_rejects_dom( 176 t, 177 "InvalidStateError", 178 request.show(), 179 "show() must reject with InvalidStateError" 180 ); 181 }, button.innerText.trim()); 182 } 183 </script> 184 <h2>updateWith() method - "abort the update"</h2> 185 <p> 186 Click on each button in sequence from top to bottom without refreshing the page. 187 Each button will bring up the Payment Request UI window. 188 </p> 189 <p> 190 When the payment sheet is shown, change the shipping address. 191 </p> 192 <ol> 193 <li> 194 <button onclick=" 195 const rejectedPromise = Promise.reject(new SyntaxError('test')); 196 testBadUpdate(this, rejectedPromise, 'AbortError'); 197 "> 198 Rejection of detailsPromise must abort the update with an "AbortError" DOMException. 199 </button> 200 </li> 201 <li> 202 <button onclick=" 203 const invalidDetails = { total: `this will cause a TypeError!` }; 204 testBadUpdate(this, invalidDetails, TypeError); 205 "> 206 Total in the update is a string, so converting to IDL must abort the update with a TypeError. 207 </button> 208 </li> 209 <li> 210 <button onclick=" 211 const invalidDetails = { total: recursiveData }; 212 testBadUpdate(this, invalidDetails, TypeError); 213 "> 214 Total is recursive, so converting to IDL must abort the update with a TypeError. 215 </button> 216 </li> 217 <li> 218 <button onclick=" 219 testBadUpdate(this, invalidDetailsNegativeTotal, TypeError); 220 "> 221 Updating with a negative total results in a TypeError. 222 </button> 223 </li> 224 <li> 225 <button onclick=" 226 const badDetails = Object.assign({}, validDetails, { displayItems: invalidPaymentItems }); 227 testBadUpdate(this, badDetails, RangeError); 228 "> 229 Updating with a displayItem with an invalid currency results in RangeError. 230 </button> 231 </li> 232 <li> 233 <button onclick=" 234 const duplicateShippingOptions = [validShippingOption, validShippingOption]; 235 const badDetails = Object.assign({}, validDetails, { shippingOptions: duplicateShippingOptions }); 236 testBadUpdate(this, badDetails, TypeError); 237 "> 238 Updating with duplicate shippingOptions (same IDs) results in a TypeError. 239 </button> 240 </li> 241 <li> 242 <button onclick=" 243 const badDetails = Object.assign({}, validDetails, { shippingOptions: invalidShippingOptions }); 244 testBadUpdate(this, badDetails, RangeError); 245 "> 246 Updating with a shippingOption with an invalid currency value results in a RangError. 247 </button> 248 </li> 249 <li> 250 <button onclick=" 251 // validModifier is there as to avoid false positives - it should just get ignored 252 const badModifiers = { modifiers: [ modifierWithInvalidTotal, validModifier ] }; 253 const badDetails = Object.assign({}, validDetails, badModifiers); 254 testBadUpdate(this, badDetails, RangeError); 255 "> 256 Must throw a RangeError when a modifier's total item has an invalid currency. 257 </button> 258 </li> 259 <li> 260 <button onclick=" 261 // validModifier is there as to avoid false positives - it should just get ignored 262 const badModifiers = { modifiers: [ modifierWithInvalidDisplayItems, validModifier ] }; 263 const badDetails = Object.assign({}, validDetails, badModifiers); 264 testBadUpdate(this, badDetails, RangeError); 265 "> 266 Must throw a RangeError when a modifier display item has an invalid currency. 267 </button> 268 </li> 269 <li> 270 <button onclick=" 271 // validModifier is there as to avoid false positives - it should just get ignored 272 const badModifiers = { modifiers: [ modifierWithRecursiveData, validModifier ] }; 273 const badDetails = Object.assign({}, validDetails, badModifiers); 274 testBadUpdate(this, badDetails, TypeError); 275 "> 276 Must throw as Modifier has a recursive dictionary. 277 </button> 278 </li> 279 <li> 280 <button onclick="done();">Done!</button> 281 </li> 282 </ol> 283 <small> 284 If you find a buggy test, please <a href="https://github.com/web-platform-tests/wpt/issues">file a bug</a> 285 and tag one of the <a href="https://github.com/web-platform-tests/wpt/blob/master/payment-request/META.yml">suggested reviewers</a>. 286 </small>