| <!doctype html> | |
| <meta charset="utf8"> | |
| <link rel="help" href="https://www.w3.org/TR/payment-request/#updatewith()-method"> | |
| <link rel="help" href="https://github.com/w3c/payment-request/pull/591"> | |
| <title> | |
| PaymentRequestUpdateEvent.updateWith() needs to be called immediately | |
| </title> | |
| <script src="/resources/testharness.js"></script> | |
| <script src="/resources/testharnessreport.js"></script> | |
| <script> | |
| setup({ explicit_done: true, explicit_timeout: true }); | |
| const validMethod = Object.freeze({ supportedMethods: "basic-card" }); | |
| const validMethods = Object.freeze([validMethod]); | |
| const validAmount = Object.freeze({ currency: "USD", value: "5.00" }); | |
| const validTotal = Object.freeze({ | |
| label: "label", | |
| amount: validAmount, | |
| }); | |
| const validShippingOptionA = Object.freeze({ | |
| id: "a-shipping-option", | |
| label: "A shipping option", | |
| amount: validAmount, | |
| selected: true, | |
| }); | |
| const validShippingOptionB = Object.freeze({ | |
| id: "b-shipping-option", | |
| label: "B shipping option", | |
| amount: validAmount, | |
| }); | |
| const validDetails = Object.freeze({ | |
| total: validTotal, | |
| shippingOptions: [validShippingOptionA, validShippingOptionB], | |
| }); | |
| const validOptions = Object.freeze({ | |
| requestShipping: true, | |
| }); | |
| function testImmediateUpdate({ textContent: testName }) { | |
| promise_test(async t => { | |
| const request = new PaymentRequest( | |
| validMethods, | |
| validDetails, | |
| validOptions | |
| ); | |
| const eventPromise = new Promise((resolve, reject) => { | |
| request.addEventListener( | |
| "shippingaddresschange", | |
| async ev => { | |
| // spin the event loop, sets [[waitForUpdate]] to true. | |
| await Promise.resolve(); | |
| try { | |
| ev.updateWith(validDetails); | |
| resolve(); // This is bad. | |
| } catch (err) { | |
| reject(err); // this is good. | |
| } | |
| }, | |
| { once: true } | |
| ); | |
| }); | |
| const response = await request.show(); | |
| await promise_rejects( | |
| t, | |
| "InvalidStateError", | |
| eventPromise, | |
| "The event loop already spun, so [[waitForUpdate]] is now true" | |
| ); | |
| await response.complete(); | |
| }, testName.trim()); | |
| } | |
| function testSubsequentUpdateWithCalls({ textContent: testName }) { | |
| promise_test(async t => { | |
| const request = new PaymentRequest( | |
| validMethods, | |
| validDetails, | |
| validOptions | |
| ); | |
| const eventPromise = new Promise((resolve, reject) => { | |
| request.addEventListener("shippingaddresschange", async ev => { | |
| const p = Promise.resolve(validDetails); | |
| ev.updateWith(p); | |
| await p; | |
| try { | |
| ev.updateWith(validDetails); | |
| resolve(); // this is bad, we should never get to here. | |
| } catch (err) { | |
| reject(err); // this is good! | |
| } | |
| }); | |
| }); | |
| const responsePromise = request.show(); | |
| await promise_rejects( | |
| t, | |
| "InvalidStateError", | |
| eventPromise, | |
| "Expected eventPromise to have rejected, because updateWith() was a called twice" | |
| ); | |
| const response = await responsePromise; | |
| await response.complete(); | |
| }, testName.trim()); | |
| } | |
| function testRecycleEvents({ textContent: testName }) { | |
| promise_test(async t => { | |
| const request = new PaymentRequest( | |
| validMethods, | |
| validDetails, | |
| validOptions | |
| ); | |
| // Register both listeners. | |
| const addressChangedPromise = new Promise(resolve => { | |
| request.addEventListener("shippingaddresschange", resolve, { | |
| once: true, | |
| }); | |
| }); | |
| const optionChangedPromise = new Promise(resolve => { | |
| request.addEventListener("shippingoptionchange", resolve, { | |
| once: true, | |
| }); | |
| }); | |
| const responsePromise = request.show(); | |
| // Let's wait for the address to change. | |
| const addressChangeEvent = await addressChangedPromise; | |
| // Sets [[waitingForUpdate]] to true. | |
| addressChangeEvent.updateWith(validDetails); | |
| // Let's wait for the shippingOption. | |
| const optionChangeEvent = await optionChangedPromise; | |
| // Here, we try to be sneaky, and reuse the addressChangeEvent to perform the update. | |
| // However, addressChangeEvent [[waitingForUpdate]] is true, so it throws. | |
| assert_throws( | |
| "InvalidStateError", | |
| () => { | |
| addressChangeEvent.updateWith(validDetails); | |
| }, | |
| "addressChangeEvent [[waitingForUpdate]] is true, so it must throw" | |
| ); | |
| // But optionChangeEvent is still usable tho, so... | |
| optionChangeEvent.updateWith(validDetails); | |
| assert_throws( | |
| "InvalidStateError", | |
| () => { | |
| optionChangeEvent.updateWith(validDetails); | |
| }, | |
| "optionChangeEvent [[waitingForUpdate]] is true, so it must throw" | |
| ); | |
| const response = await responsePromise; | |
| await response.complete(); | |
| }, testName.trim()); | |
| } | |
| </script> | |
| <h2>updateWith() method</h2> | |
| <p> | |
| Click on each button in sequence from top to bottom without refreshing the page. | |
| Each button will bring up the Payment Request UI window. | |
| </p> | |
| <p> | |
| When the payment sheet is shown, select a different shipping address once. Then pay. | |
| </p> | |
| <ol> | |
| <li id="test-0"> | |
| <button onclick="testImmediateUpdate(this);"> | |
| updateWith() must be called immediately, otherwise must throw an InvalidStateError. | |
| </button> | |
| </li> | |
| <li id="test-1"> | |
| <button onclick="testSubsequentUpdateWithCalls(this);"> | |
| Once the event has performed an update, subsequent calls to updateWith() must throw InvalidStateError. | |
| </button> | |
| </li> | |
| <li id="test-2"> | |
| <button onclick="testRecycleEvents(this);"> | |
| Recycling events must not be possible. | |
| </button> When the payment sheet is shown, select a different shipping address once, then change shipping option once. Then pay. | |
| </li> | |
| <li> | |
| <button onclick="done();">Done!</button> | |
| </li> | |
| </ol> | |
| <small> | |
| If you find a buggy test, please <a href="https://github.com/w3c/web-platform-tests/issues">file a bug</a> | |
| and tag one of the <a href="https://github.com/w3c/web-platform-tests/blob/master/payment-request/OWNERS">owners</a>. | |
| </small> |