diff options
Diffstat (limited to 'testing/web-platform/tests/payment-request/PaymentRequestUpdateEvent')
6 files changed, 925 insertions, 2 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> diff --git a/testing/web-platform/tests/payment-request/PaymentRequestUpdateEvent/updateWith-duplicate-shipping-options-manual.https.html b/testing/web-platform/tests/payment-request/PaymentRequestUpdateEvent/updateWith-duplicate-shipping-options-manual.https.html new file mode 100644 index 0000000000..a4a7afd7f6 --- /dev/null +++ b/testing/web-platform/tests/payment-request/PaymentRequestUpdateEvent/updateWith-duplicate-shipping-options-manual.https.html @@ -0,0 +1,106 @@ +<!doctype html> +<meta charset="utf8"> +<link rel="help" href="https://w3c.github.io/payment-request/#updatewith()-method"> +<title> + updateWith() method - duplicate shippingOption ids +</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 = [validMethod, applePay]; +const validAmount = Object.freeze({ + currency: "USD", + value: "5.00", +}); +const validShippingOption = Object.freeze({ + id: "option1", + label: "Option 1", + amount: validAmount, + selected: true, +}); +const validShippingOptions = Object.freeze([validShippingOption]); +const validDetails = Object.freeze({ + total: { + label: "Total due", + amount: validAmount, + }, + shippingOptions: validShippingOptions, +}); +const validOptions = Object.freeze({ + requestShipping: true, +}); + +test(() => { + try { + const request = new PaymentRequest(validMethods, validDetails); + } catch (err) { + done(); + throw err; + } +}, "Must construct a PaymentRequest (smoke test)"); + +function testFireEvents(button) { + button.disabled = true; + promise_test(async t => { + const request = new PaymentRequest( + validMethods, + validDetails, + validOptions + ); + request.addEventListener("shippingaddresschange", event => { + // Same option, so duplicate ids + const otherShippingOption = Object.assign({}, validShippingOption, { + id: "other", + }); + const shippingOptions = [ + validShippingOption, + otherShippingOption, + validShippingOption, + ]; + const newDetails = Object.assign({}, validDetails, { shippingOptions }); + event.updateWith(newDetails); + }); + const acceptPromise = request.show(); + await promise_rejects_js( + t, + TypeError, + acceptPromise, + "Duplicate shippingOption ids must abort with TypeError" + ); + }, button.textContent.trim()); + done(); +} +</script> +<h2>updateWith() method - duplicate shippingOptions ids</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. + If you have to manually abort the test from the payment sheet, then the + test has failed. +</p> +<ol> + <li> + <button onclick="testFireEvents(this)"> + If there are duplicate shippingOption ids, then abort payment request. + </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> diff --git a/testing/web-platform/tests/payment-request/PaymentRequestUpdateEvent/updateWith-incremental-update-manual.https.html b/testing/web-platform/tests/payment-request/PaymentRequestUpdateEvent/updateWith-incremental-update-manual.https.html new file mode 100644 index 0000000000..c1ed1b5f68 --- /dev/null +++ b/testing/web-platform/tests/payment-request/PaymentRequestUpdateEvent/updateWith-incremental-update-manual.https.html @@ -0,0 +1,196 @@ +<!doctype html> +<meta charset="utf8"> +<link rel="help" href="https://w3c.github.io/payment-request/#updatewith-method"> +<title> + Incremental updates via updateWith() +</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> +setup({ + explicit_done: true, + explicit_timeout: true, +}); + +const methods = [{ + supportedMethods: "basic-card", +}, { + supportedMethods: "https://apple.com/apple-pay", + data: { + version: 3, + merchantIdentifier: "merchant.com.example", + countryCode: "US", + merchantCapabilities: ["supports3DS"], + supportedNetworks: ["visa"], + } +}]; + +const options = { + requestShipping: true, +}; + +const initialDetails = { + total: { + label: "Initial total", + amount: { + currency: "USD", + value: "1.0", + }, + }, + shippingOptions: [ + { + id: "neutral", + label: "NEUTRAL SHIPPING OPTION", + selected: true, + amount: { + currency: "USD", + value: "0.00", + }, + }, + ], +}; + +function testFireEvent(button, updateDetails) { + button.disabled = true; + const request = new PaymentRequest(methods, initialDetails, options); + const handlerPromise = new Promise(resolve => { + request.onshippingaddresschange = event => { + event.updateWith(updateDetails); + resolve(event); + }; + }); + promise_test(async t => { + const response = await request.show(); + const event = await handlerPromise; + await response.complete("success"); + }, button.textContent.trim()); +} + +</script> +<h2> + Incremental updates +</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> + Unless stated otherwise, each test will update some part of the displayed payment sheet in + a manner indicated below. When prompted, please change or enter a new + shipping address, look for the tested change, and complete the payment. +</p> +<p> + If the payment request locks up or otherwise aborts, the test has failed. +</p> +<ol> + <li> + <button onclick="testFireEvent(this, {});"> + Passing an empty dictionary does not cause the sheet to change. + No values in the sheet must change. + </button> + </li> +</ol> + +<section> + <h3>Incremental updates via PaymentDetailsUpdate.total</h3> + <ol> + <li> + <button onclick=" + const total = { + label: 'PASS', + amount: { + currency: 'XXX', + value: '20', + }, + }; + const updatedDetails = { total }; + testFireEvent(this, updatedDetails);"> + After changing shipping address, the total becomes XXX20, with the label "PASS". + </button> + </li> + </ol> +</section> + +<section> + <h3>Incremental updates via PaymentDetailsBase.displayItems</h3> + <ol> + <li> + <button onclick=" + const item = { + label: 'PASS', + amount: { currency: 'ABC', value: '55.00' }, + }; + const updatedDetails = { + displayItems: [ item ] + }; + testFireEvent(this, updatedDetails);"> + After changing shipping address, a new display item is shown + with a with label PASS, and value of ABC55.00. + </button> + </li> + </ol> +</section> + +<section> + <h3>Incremental updates via PaymentDetailsBase.shippingOptions</h3> + <ol> + <li> + <button onclick=" + const shippingOptions = [ + { + id: 'pass', + label: 'PASS', + amount: { currency: 'USD', value: '1.00' }, + selected: true, + }, + { + id: 'fail', + label: 'FAIL IF THIS IS SELECTED', + amount: { currency: 'USD', value: '25.00' } + }, + ]; + const updatedDetails = { + shippingOptions + }; + testFireEvent(this, updatedDetails);"> + After changing shipping address, two new shipping options appear. + The shipping option labelled "PASS" with a value of USD1.0 is selected. + </button> + </li> + </ol> +</section> + +<section> + <h3>Incremental updates via PaymentDetailsBase.modifiers</h3> + <ol> + <li> + <button onclick=" + const additionalItem = { + label: 'PASS-DISPLAY-ITEM', + amount: { currency: 'USD', value: '3.00' }, + }; + const modifiers = [{ + additionalDisplayItems: [ additionalItem ], + supportedMethods: 'basic-card', + total: { + label: 'PASS-TOTAL', + amount: { currency: 'USD', value: '123.00' }, + }, + }]; + const updatedDetails = { modifiers }; + testFireEvent(this, updatedDetails);"> + After changing shipping address, a new display item is shown + with a with label PASS-DISPLAY-ITEM, and value of ABC55.00 and the total is + labelled PASS-TOTAL with a value of USD123.0 + </button> + </li> + <li> + <button onclick="done()">DONE - see results</button> + </li> + </ol> +</section> + +<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> diff --git a/testing/web-platform/tests/payment-request/PaymentRequestUpdateEvent/updateWith-method-abort-update-manual.https.html b/testing/web-platform/tests/payment-request/PaymentRequestUpdateEvent/updateWith-method-abort-update-manual.https.html new file mode 100644 index 0000000000..e24452c2a9 --- /dev/null +++ b/testing/web-platform/tests/payment-request/PaymentRequestUpdateEvent/updateWith-method-abort-update-manual.https.html @@ -0,0 +1,286 @@ +<!doctype html> +<meta charset="utf8"> +<link rel="help" href="https://w3c.github.io/payment-request/#dfn-abort-the-update"> +<title> + updateWith() method - "abort the update" +</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> +setup({ explicit_done: true, explicit_timeout: true }); + +// PaymentMethod +const validMethod = Object.freeze({ + supportedMethods: "valid-but-wont-ever-match", +}); + +const validMethodBasicCard = Object.freeze({ + supportedMethods: "basic-card", +}); + +const applePay = Object.freeze({ + supportedMethods: "https://apple.com/apple-pay", + data: { + version: 3, + merchantIdentifier: "merchant.com.example", + countryCode: "US", + merchantCapabilities: ["supports3DS"], + supportedNetworks: ["visa"], + } +}); + +// Methods +const validMethods = Object.freeze([validMethodBasicCard, validMethod, applePay]); + +// Amounts +const validAmount = Object.freeze({ + currency: "USD", + value: "1.00", +}); + +const invalidAmount = Object.freeze({ + currency: "¡INVALID!", + value: "A1.0", +}); + +const negativeAmount = Object.freeze({ + currency: "USD", + value: "-1.00", +}); + +// Totals +const validTotal = Object.freeze({ + label: "Valid Total", + amount: validAmount, +}); + +const invalidTotal = Object.freeze({ + label: "Invalid Total", + amount: invalidAmount, +}); + +const invalidNegativeTotal = Object.freeze({ + label: "Invalid negative total", + amount: negativeAmount, +}); + +// PaymentDetailsInit +const validDetails = Object.freeze({ + total: validTotal, +}); + +const invalidDetailsNegativeTotal = Object.freeze({ + total: invalidNegativeTotal, +}); + +// PaymentOptions +const validOptions = Object.freeze({ + requestShipping: true, +}); + +// PaymentItem +const validPaymentItem = Object.freeze({ + amount: validAmount, + label: "Valid payment item", +}); + +const invalidPaymentItem = Object.freeze({ + amount: invalidAmount, + label: "Invalid payment item", +}); + +// PaymentItem +const validPaymentItems = Object.freeze([validPaymentItem]); +const invalidPaymentItems = Object.freeze([invalidPaymentItem]); + +// PaymentShippingOption +const invalidShippingOption = Object.freeze({ + id: "abc", + label: "Invalid shipping option", + amount: invalidAmount, + selected: true, +}); + +// PaymentShippingOptions +const validShippingOption = Object.freeze({ + id: "abc", + label: "valid shipping option", + amount: validAmount, +}); + +const validShippingOptions = Object.freeze([validShippingOption]); +const invalidShippingOptions = Object.freeze([invalidShippingOption]); + +// PaymentDetailsModifier +const validModifier = Object.freeze({ + additionalDisplayItems: validPaymentItems, + supportedMethods: "valid-but-wont-ever-match", + total: validTotal, +}); + +const modifierWithInvalidDisplayItems = Object.freeze({ + additionalDisplayItems: invalidPaymentItems, + supportedMethods: "basic-card", + total: validTotal, +}); + +const modifierWithValidDisplayItems = Object.freeze({ + additionalDisplayItems: validPaymentItems, + supportedMethods: "basic-card", + total: validTotal, +}); + +const modifierWithInvalidTotal = Object.freeze({ + additionalDisplayItems: validPaymentItems, + supportedMethods: "basic-card", + total: invalidTotal, +}); + +const recursiveData = {}; +recursiveData.foo = recursiveData; +Object.freeze(recursiveData); + +const modifierWithRecursiveData = Object.freeze({ + supportedMethods: "basic-card", + total: validTotal, + data: recursiveData, +}); + +function testBadUpdate(button, badDetails, expectedError, errorCode) { + button.disabled = true; + promise_test(async t => { + const request = new PaymentRequest( + validMethods, + validDetails, + validOptions + ); + request.onshippingaddresschange = event => { + event.updateWith(badDetails); + }; + // First we check the bad update. + const acceptPromise = request.show(); + let test_func; + if (typeof expectedError == "function") { + test_func = promise_rejects_js; + } else { + test_func = promise_rejects_dom; + } + await test_func( + t, + expectedError, + acceptPromise, + "badDetails must cause acceptPromise to reject with expectedError" + ); + // The request [[state]] is now "closed", so let's check for InvalidStateError + await promise_rejects_dom( + t, + "InvalidStateError", + request.show(), + "show() must reject with InvalidStateError" + ); + }, button.innerText.trim()); +} +</script> +<h2>updateWith() method - "abort the update"</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, change the shipping address. +</p> +<ol> + <li> + <button onclick=" + const rejectedPromise = Promise.reject(new SyntaxError('test')); + testBadUpdate(this, rejectedPromise, 'AbortError'); + "> + Rejection of detailsPromise must abort the update with an "AbortError" DOMException. + </button> + </li> + <li> + <button onclick=" + const invalidDetails = { total: `this will cause a TypeError!` }; + testBadUpdate(this, invalidDetails, TypeError); + "> + Total in the update is a string, so converting to IDL must abort the update with a TypeError. + </button> + </li> + <li> + <button onclick=" + const invalidDetails = { total: recursiveData }; + testBadUpdate(this, invalidDetails, TypeError); + "> + Total is recursive, so converting to IDL must abort the update with a TypeError. + </button> + </li> + <li> + <button onclick=" + testBadUpdate(this, invalidDetailsNegativeTotal, TypeError); + "> + Updating with a negative total results in a TypeError. + </button> + </li> + <li> + <button onclick=" + const badDetails = Object.assign({}, validDetails, { displayItems: invalidPaymentItems }); + testBadUpdate(this, badDetails, RangeError); + "> + Updating with a displayItem with an invalid currency results in RangeError. + </button> + </li> + <li> + <button onclick=" + const duplicateShippingOptions = [validShippingOption, validShippingOption]; + const badDetails = Object.assign({}, validDetails, { shippingOptions: duplicateShippingOptions }); + testBadUpdate(this, badDetails, TypeError); + "> + Updating with duplicate shippingOptions (same IDs) results in a TypeError. + </button> + </li> + <li> + <button onclick=" + const badDetails = Object.assign({}, validDetails, { shippingOptions: invalidShippingOptions }); + testBadUpdate(this, badDetails, RangeError); + "> + Updating with a shippingOption with an invalid currency value results in a RangError. + </button> + </li> + <li> + <button onclick=" + // validModifier is there as to avoid false positives - it should just get ignored + const badModifiers = { modifiers: [ modifierWithInvalidTotal, validModifier ] }; + const badDetails = Object.assign({}, validDetails, badModifiers); + testBadUpdate(this, badDetails, RangeError); + "> + Must throw a RangeError when a modifier's total item has an invalid currency. + </button> + </li> + <li> + <button onclick=" + // validModifier is there as to avoid false positives - it should just get ignored + const badModifiers = { modifiers: [ modifierWithInvalidDisplayItems, validModifier ] }; + const badDetails = Object.assign({}, validDetails, badModifiers); + testBadUpdate(this, badDetails, RangeError); + "> + Must throw a RangeError when a modifier display item has an invalid currency. + </button> + </li> + <li> + <button onclick=" + // validModifier is there as to avoid false positives - it should just get ignored + const badModifiers = { modifiers: [ modifierWithRecursiveData, validModifier ] }; + const badDetails = Object.assign({}, validDetails, badModifiers); + testBadUpdate(this, badDetails, TypeError); + "> + Must throw as Modifier has a recursive dictionary. + </button> + </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> diff --git a/testing/web-platform/tests/payment-request/PaymentRequestUpdateEvent/updateWith-state-checks-manual.https.html b/testing/web-platform/tests/payment-request/PaymentRequestUpdateEvent/updateWith-state-checks-manual.https.html new file mode 100644 index 0000000000..fb16de5699 --- /dev/null +++ b/testing/web-platform/tests/payment-request/PaymentRequestUpdateEvent/updateWith-state-checks-manual.https.html @@ -0,0 +1,125 @@ +<!doctype html> +<meta charset="utf8"> +<link rel="help" href="https://www.w3.org/TR/payment-request/#updatewith()-method"> +<title>updateWith() method - state machine checks</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 validShippingOption = Object.freeze({ + id: "a-shipping-option", + label: "A shipping option", + amount: validAmount, + selected: true, +}); +const validDetails = Object.freeze({ + total: validTotal, + shippingOptions: [validShippingOption], +}); +const validOptions = Object.freeze({ + requestShipping: true, +}); + +function getPaymentPromises() { + const request = new PaymentRequest(validMethods, validDetails, validOptions); + const eventPromise = new Promise(resolve => { + request.addEventListener("shippingaddresschange", resolve); + }); + const responsePromise = request.show(); + return { eventPromise, responsePromise }; +} + +function testRequestIsClosed(button) { + button.disabled = "true"; + promise_test(async t => { + const { eventPromise, responsePromise } = getPaymentPromises(); + const event = await eventPromise; + // We are going to abort the responsePromise, so we can ignore error. + responsePromise.catch(err => err); + // Set request.[[state]] to closed + await event.target.abort(); + assert_throws_dom( + "InvalidStateError", + () => { + event.updateWith(validDetails); + }, + "request.[[state]] is not interactive, must throw an InvalidStateError." + ); + responsePromise.catch(err => err); + }, button.textContent.trim()); +} + +function testRequestIsUpdating(button) { + button.disabled = "true"; + promise_test(async t => { + const { eventPromise, responsePromise } = getPaymentPromises(); + const event = await eventPromise; + // We are going to put a promise into a pending state + // check that a second call to updateWith() throws, + // then resolve the pending promise below. + let resolver; + const pendingPromise = new Promise(resolve => { + resolver = resolve; + }); + // Set request.[[updating]] to true + event.updateWith(pendingPromise); + assert_throws_dom( + "InvalidStateError", + () => { + event.updateWith(validDetails); + }, + "request.[[updating]] to true, must throw an InvalidStateError." + ); + // We got the error we wanted, so let's resolve with valid details. + resolver(validDetails); + await pendingPromise; + await event.target.abort(); + responsePromise.catch(err => err); + }, button.textContent.trim()); +} + +</script> +<h2>updateWith() method - state machine checks</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="testRequestIsClosed(this);"> + When updateWith() is called, if request.[[state]] is not "interactive", then throw an " InvalidStateError" DOMException. + </button> + </li> + <li id="test-1"> + <button onclick="testRequestIsUpdating(this);"> + When updateWith() is called, If request.[[updating]] is true, then throw an "InvalidStateError" DOMException. + </button> + </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> diff --git a/testing/web-platform/tests/payment-request/PaymentRequestUpdateEvent/updatewith-method.https.html b/testing/web-platform/tests/payment-request/PaymentRequestUpdateEvent/updatewith-method.https.html index 9a60fe7a4c..fffd3b3ec5 100644 --- a/testing/web-platform/tests/payment-request/PaymentRequestUpdateEvent/updatewith-method.https.html +++ b/testing/web-platform/tests/payment-request/PaymentRequestUpdateEvent/updatewith-method.https.html @@ -29,7 +29,9 @@ test(() => { // Github issue: https://github.com/w3c/browser-payment-api/issues/546 test(() => { const untrustedEvents = [ - new PaymentRequestUpdateEvent("just a test") + new PaymentRequestUpdateEvent("just a test"), + new PaymentRequestUpdateEvent("shippingaddresschange"), + new PaymentRequestUpdateEvent("shippingoptionchange"), ].forEach(ev => { assert_throws_dom( "InvalidStateError", @@ -45,7 +47,9 @@ test(() => { test(() => { const request = new PaymentRequest(defaultMethods, defaultDetails); const untrustedEvents = [ - new PaymentRequestUpdateEvent("just a test") + new PaymentRequestUpdateEvent("just a test"), + new PaymentRequestUpdateEvent("shippingaddresschange"), + new PaymentRequestUpdateEvent("shippingoptionchange"), ].map(ev => { request.dispatchEvent(ev); // set .target and dispatch flag // unstrusted event. |