| <!doctype html> |
| <meta charset="utf8"> |
| <link rel="help" href="https://w3c.github.io/payment-request/#dom-paymentresponse-retry"> |
| <title> |
| PaymentResponse.prototype.retry() method |
| </title> |
| <script src="/resources/testharness.js"></script> |
| <script src="/resources/testharnessreport.js"></script> |
| <script src="helpers.js"></script> |
| <script> |
| test(() => { |
| assert_true( |
| "retry" in PaymentResponse.prototype, |
| "retry must be in prototype" |
| ); |
| assert_true( |
| PaymentResponse.prototype.retry instanceof Function, |
| "retry must be a function" |
| ); |
| }, "PaymentResponse.prototype must have a retry() function (smoke test)."); |
| |
| function checkCompletedCantRetry(button) { |
| button.disabled = true; |
| promise_test(async t => { |
| const { response } = await getPaymentRequestResponse(); |
| // sets response.[[complete]] to true. |
| await response.complete("success"); |
| return promise_rejects( |
| t, |
| "InvalidStateError", |
| response.retry(), |
| "response.[[complete]] is true, so rejects with InvalidStateError." |
| ); |
| }, button.textContent.trim()); |
| } |
| |
| function repeatedCallsToRetry(button) { |
| button.disabled = true; |
| promise_test(async t => { |
| const { response } = await getPaymentRequestResponse(); |
| const retryPromise = response.retry(); |
| await promise_rejects( |
| t, |
| "InvalidStateError", |
| response.retry(), |
| "Calling retry() again rejects with an InvalidStateError" |
| ); |
| await retryPromise; |
| await response.complete("success"); |
| }, button.textContent.trim()); |
| } |
| |
| function callCompleteWhileRetrying(button) { |
| button.disabled = true; |
| promise_test(async t => { |
| const { response } = await getPaymentRequestResponse(); |
| const retryPromise = response.retry(); |
| await promise_rejects( |
| t, |
| "InvalidStateError", |
| response.complete("success"), |
| "Calling complete() while retrying rejects with an InvalidStateError" |
| ); |
| await retryPromise; |
| await response.complete("success"); |
| }, button.textContent.trim()); |
| } |
| |
| function callingRequestAbortMustNotAbort(button) { |
| button.disabled = true; |
| promise_test(async t => { |
| const { response, request } = await getPaymentRequestResponse(); |
| const retryPromise = response.retry(); |
| await promise_rejects( |
| t, |
| "InvalidStateError", |
| request.abort(), |
| "Calling request.abort() while retrying rejects with an InvalidStateError" |
| ); |
| await retryPromise; |
| await response.complete("success"); |
| }, button.textContent.trim()); |
| } |
| |
| function canRetryMultipleTimes(button) { |
| button.disabled = true; |
| promise_test(async t => { |
| const { response } = await getPaymentRequestResponse(); |
| assert_equals( |
| await response.retry(), |
| undefined, |
| "Expected undefined as the resolve value" |
| ); |
| assert_equals( |
| await response.retry(), |
| undefined, |
| "Expected undefined as the resolve value" |
| ); |
| await response.complete("success"); |
| await promise_rejects( |
| t, |
| "InvalidStateError", |
| response.retry(), |
| "Calling retry() after complete() rejects with a InvalidStateError" |
| ); |
| }, button.textContent.trim()); |
| } |
| |
| function userCanAbortARetry(button) { |
| button.disabled = true; |
| promise_test(async t => { |
| const { response } = await getPaymentRequestResponse(); |
| await promise_rejects( |
| t, |
| "AbortError", |
| response.retry(), |
| "The user aborting a retry rejects with a AbortError" |
| ); |
| await promise_rejects( |
| t, |
| "InvalidStateError", |
| response.retry(), |
| "After the user aborts, response [[complete]] is true so retry() must reject with InvalidStateError" |
| ); |
| await promise_rejects( |
| t, |
| "InvalidStateError", |
| response.complete("success"), |
| "After the user aborts, response [[complete]] is true, so complete() rejects with a InvalidStateError" |
| ); |
| }, button.textContent.trim()); |
| } |
| |
| function userIsShownErrorsFields(button) { |
| button.disabled = true; |
| promise_test(async t => { |
| const { response, request } = await getPaymentRequestResponse({ requestShipping: true }); |
| const retryPromise = response.retry({ |
| shippingAddress: { city: "Invalid city", addressLine: "Invalid address line" }, |
| }); |
| await retryPromise; |
| await response.complete("success"); |
| }, button.textContent.trim()); |
| } |
| |
| function abortTheUpdate(button) { |
| button.disabled = true; |
| promise_test(async t => { |
| const { response, request } = await getPaymentRequestResponse({ requestShipping: true }); |
| // causes "abort the update" to run |
| const shippingChangedPromise = new Promise(resolve => { |
| request.onshippingoptionchange = () => { |
| event.updateWith({ total: { amount: { currency: "USD", value: "INVALID" } }}); |
| resolve(); |
| }; |
| }); |
| const retryPromise = response.retry(); |
| await shippingChangedPromise; |
| await promise_rejects( |
| t, |
| new TypeError(), |
| retryPromise, |
| "retry() aborts with a TypeError, because totals' value is invalid" |
| ); |
| await promise_rejects( |
| t, |
| "InvalidStateError", |
| response.complete("success"), |
| "After the user aborts, response [[complete]] is true, so complete() rejects with a InvalidStateError" |
| ); |
| }, button.textContent.trim()); |
| } |
| |
| function callingRetryReturnsUniquePromise(button){ |
| button.disabled = true; |
| promise_test(async t => { |
| const { response } = await getPaymentRequestResponse(); |
| const retryPromise = response.retry(); |
| const promises = new Set([ |
| retryPromise, |
| response.retry(), |
| response.retry(), |
| ]); |
| assert_equals(promises.size, 3, "Must have three unique objects"); |
| await retryPromise; |
| await response.complete(); |
| }, button.textContent.trim()); |
| }; |
| |
| |
| </script> |
| <h2> |
| Manual Tests for PaymentResponse.retry() - Please run in order! |
| </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 presented with the payment sheet, use any credit card select to "Pay" multiple times. |
| </p> |
| <ol> |
| <li> |
| <button onclick="checkCompletedCantRetry(this);"> |
| A completed payment request cannot be retried. |
| </button> |
| </li> |
| <li> |
| <button onclick="repeatedCallsToRetry(this);"> |
| Calling retry() more than once yield a rejected promise, but the |
| retryPromise resolves independently. |
| </button> |
| </li> |
| <li> |
| <button onclick="callCompleteWhileRetrying(this);"> |
| Calling complete() while a retry() is in progress results in an InvalidStateError. |
| </button> |
| </li> |
| <li> |
| <button onclick="callingRequestAbortMustNotAbort(this);"> |
| Trying to abort() via PaymentRequest is not possible. |
| </button> |
| </li> |
| <li> |
| <button onclick="canRetryMultipleTimes(this);"> |
| It's possible to retry() multiple times and eventually complete(). |
| After complete(), however, retry() rejects with an InvalidStateError. |
| </button> |
| </li> |
| <li> |
| <p> |
| When shown the payment sheet, hit pay once, then abort retrying the payment. |
| </p> |
| <button onclick="userCanAbortARetry(this);"> |
| The user aborting retrying a payment causes the retryPromise to reject with AbortError. |
| Aborting a payment is causes it complete. |
| </button> |
| </li> |
| <li> |
| <p> |
| When shown the payment sheet, hit pay once. Check payment sheet for error fields. |
| Then hit escape or otherwise abort the payment. |
| </p> |
| <button onclick="userIsShownErrorsFields(this);"> |
| When retrying, the user is shown error fields to fix. |
| </button> |
| </li> |
| <li> |
| <p> |
| When shown the payment sheet, hit pay once. Then retry once. |
| </p> |
| <button onclick="abortTheUpdate(this);"> |
| When "abort the update" occurs because of an update error, |
| the `retryPromise` is rejected and response.[[complete]] becomes true. |
| </button> |
| </li> |
| <li> |
| <p> |
| When shown the payment sheet, hit pay once. Then retry once. |
| </p> |
| <button onclick="callingRetryReturnsUniquePromise(this);"> |
| Calling retry() multiple times is always a new object. |
| </button> |
| </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> |