summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/payment-request/PaymentRequestUpdateEvent/updateWith-call-immediate-manual.https.html
diff options
context:
space:
mode:
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.html206
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>