diff options
Diffstat (limited to 'testing/web-platform/tests/payment-request/PaymentRequestUpdateEvent/updateWith-call-immediate-manual.https.html')
-rw-r--r-- | testing/web-platform/tests/payment-request/PaymentRequestUpdateEvent/updateWith-call-immediate-manual.https.html | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/testing/web-platform/tests/payment-request/PaymentRequestUpdateEvent/updateWith-call-immediate-manual.https.html b/testing/web-platform/tests/payment-request/PaymentRequestUpdateEvent/updateWith-call-immediate-manual.https.html new file mode 100644 index 0000000000..1365ecefeb --- /dev/null +++ b/testing/web-platform/tests/payment-request/PaymentRequestUpdateEvent/updateWith-call-immediate-manual.https.html @@ -0,0 +1,206 @@ +<!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 applePay = Object.freeze({ + supportedMethods: "https://apple.com/apple-pay", + data: { + version: 3, + merchantIdentifier: "merchant.com.example", + countryCode: "US", + merchantCapabilities: ["supports3DS"], + supportedNetworks: ["visa"], + } +}); +const validMethod = Object.freeze({ supportedMethods: "basic-card" }); +const validMethods = Object.freeze([validMethod, applePay]); +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", + ev => { + // Forces updateWith() to be run in the next event loop tick so that + // [[waitForUpdate]] is already true when it runs. + t.step_timeout(() => { + try { + ev.updateWith(validDetails); + resolve(); // This is bad. + } catch (err) { + reject(err); // this is good. + } + }); + }, + { once: true } + ); + }); + const acceptPromise = request.show(); + await promise_rejects_dom( + t, + "InvalidStateError", + eventPromise, + "The event loop already spun, so [[waitForUpdate]] is now true" + ); + const response = await acceptPromise; + 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_dom( + 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_dom( + "InvalidStateError", + () => { + addressChangeEvent.updateWith(validDetails); + }, + "addressChangeEvent [[waitingForUpdate]] is true, so it must throw" + ); + + // But optionChangeEvent is still usable tho, so... + optionChangeEvent.updateWith(validDetails); + + assert_throws_dom( + "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/web-platform-tests/wpt/issues">file a bug</a> + and tag one of the <a href="https://github.com/web-platform-tests/wpt/blob/master/payment-request/META.yml">suggested reviewers</a>. +</small> |