| <!DOCTYPE html> | |
| <meta charset="utf-8"> | |
| <title>Test for PaymentRequest.show(optional promise) method</title> | |
| <link rel="help" href="https://w3c.github.io/browser-payment-api/#show-method"> | |
| <script src="/resources/testharness.js"></script> | |
| <script src="/resources/testharnessreport.js"></script> | |
| <script> | |
| "use strict"; | |
| setup({ | |
| allow_uncaught_exception: true, | |
| explicit_done: true, | |
| explicit_timeout: true, | |
| }); | |
| // DATA USED BY TESTS | |
| // PaymentMethods | |
| const validMethods = Object.freeze([ | |
| { | |
| supportedMethods: "valid-but-wont-ever-match", | |
| }, | |
| { | |
| supportedMethods: "basic-card", | |
| }, | |
| { | |
| supportedMethods: "https://apple.com/apple-pay", | |
| data: { | |
| version: 3, | |
| merchantIdentifier: "merchant.com.example", | |
| countryCode: "US", | |
| merchantCapabilities: ["supports3DS"], | |
| supportedNetworks: ["visa"], | |
| } | |
| }, | |
| ]); | |
| // Amounts | |
| const failAmount = Object.freeze({ | |
| currency: "USD", | |
| value: "1.00", | |
| }); | |
| const passAmount = Object.freeze({ | |
| currency: "CAD", | |
| value: "50.00", | |
| }); | |
| const neutralAmount = Object.freeze({ | |
| currency: "AUD", | |
| value: "0.00", | |
| }); | |
| // Labels | |
| const failLabel = "💥 TEST HAS FAILED 💥"; | |
| const passLabel = "✅ TEST HAS PASSED ✅"; | |
| const neutralLabel = "Ignore this label"; | |
| // Totals | |
| const failTotal = Object.freeze({ | |
| label: failLabel, | |
| amount: failAmount, | |
| }); | |
| const passTotal = Object.freeze({ | |
| label: passLabel, | |
| amount: passAmount, | |
| }); | |
| const neutralTotal = Object.freeze({ | |
| label: neutralLabel, | |
| amount: passAmount, | |
| }); | |
| // PaymentItem | |
| const failPaymentItem = Object.freeze({ | |
| amount: failAmount, | |
| label: failLabel, | |
| }); | |
| const failPaymentItems = Object.freeze([failPaymentItem]); | |
| const passPaymentItem = Object.freeze({ | |
| amount: passAmount, | |
| label: passLabel, | |
| }); | |
| const passPaymentItems = Object.freeze([passPaymentItem]); | |
| // PaymentShippingOptions | |
| const failShippingOption = Object.freeze({ | |
| id: "fail", | |
| label: failLabel, | |
| amount: failAmount, | |
| }); | |
| const failShippingOptions = Object.freeze([failShippingOption]); | |
| const neutralShippingOption = Object.freeze({ | |
| id: "neutral", | |
| label: neutralLabel, | |
| amount: neutralAmount, | |
| }); | |
| const updatedShippingOption1 = Object.freeze({ | |
| id: "updated-1", | |
| label: `${passLabel} - option 1`, | |
| amount: passAmount, | |
| }); | |
| const updatedShippingOption2 = Object.freeze({ | |
| id: "updated-2", | |
| label: `${passLabel} - option 2 (MUST BE SELECTED!)`, | |
| amount: passAmount, | |
| selected: true, | |
| }); | |
| const passShippingOptions = Object.freeze([ | |
| updatedShippingOption1, | |
| updatedShippingOption2, | |
| ]); | |
| // Modifiers | |
| // create a modifier objects for each validMethods | |
| // and single additional display item | |
| const failModifiers = validMethods.map(modifier => { | |
| const label = `${failLabel} - (${modifier.supportedMethods})`; | |
| return { | |
| ...modifier, | |
| total: { | |
| ...failTotal, | |
| label, | |
| }, | |
| additionalDisplayItems: [ | |
| { | |
| ...failPaymentItem, | |
| label, | |
| }, | |
| ], | |
| }; | |
| }); | |
| // Updates the total for each, and changes the additionalDisplayItems | |
| const passModifiers = failModifiers.map(modifier => { | |
| const label = `${passLabel} - (${modifier.supportedMethods})`; | |
| return { | |
| ...modifier, | |
| total: { | |
| ...passTotal, | |
| label, | |
| }, | |
| additionalDisplayItems: [ | |
| { | |
| ...passPaymentItem, | |
| label, | |
| }, | |
| ], | |
| }; | |
| }); | |
| // PaymentDetailsInit | |
| const failDetails = Object.freeze({ | |
| displayItems: failPaymentItems, | |
| id: "this cannot be changed", | |
| modifiers: failModifiers, | |
| shippingOptions: failShippingOptions, | |
| total: failTotal, | |
| }); | |
| const neutralDetails = Object.freeze({ | |
| displayItems: [], | |
| modifiers: [], | |
| shippingOptions: [neutralShippingOption], | |
| total: neutralTotal, | |
| }); | |
| function smokeTest() { | |
| promise_test(async t => { | |
| const request = new PaymentRequest(validMethods, failDetails); | |
| await promise_rejects_js( | |
| t, | |
| TypeError, | |
| request.show({ | |
| total: "This throws a TypeError", | |
| }), | |
| "expected TypeError" | |
| ); | |
| }, "smoke test - checks if the optional details are supported on show() method"); | |
| } | |
| function runUpdateDetailsAlgorithm( | |
| buttonElement, | |
| details, | |
| options = { | |
| requestShipping: true, | |
| }, | |
| initialDetails = failDetails, | |
| ) { | |
| const testAssertion = buttonElement.textContent.trim(); | |
| buttonElement.disabled = true; | |
| promise_test(async t => { | |
| const request = new PaymentRequest(validMethods, initialDetails, options); | |
| const detailsPromise = Promise.resolve(details); | |
| const acceptPromise = request.show(detailsPromise); | |
| assert_equals(request.id, "this cannot be changed", "id must never change."); | |
| await promise_rejects_dom( | |
| t, | |
| "AbortError", | |
| acceptPromise, | |
| "expected AbortError" | |
| ); | |
| }, testAssertion); | |
| } | |
| </script> | |
| <h2> | |
| PaymentRequest <code>.show(optional detailsPromise)</code> tests | |
| </h2> | |
| <p> | |
| These test cause <code>detailsPromise</code> to resolve successfully with some updated value. As such, that will cause | |
| something in the payment sheet to change. Each test describes what is expected to change - if anything. | |
| </p> | |
| <p> | |
| <strong>Instructions:</strong> Click on each button in sequence from top to bottom without refreshing the page. The payment | |
| sheet will be shown. If required, confirm that the expected value appears in the payment sheet. Finally, manually abort/cancel | |
| the payment request by closing the payment sheet. | |
| </p> | |
| <ol> | |
| <li><button onclick="smokeTest()">If the payment sheet is shown, the test has failed.</button></li> | |
| <li><button onclick=" | |
| const details = { | |
| ...neutralDetails, | |
| id: 'fail', | |
| }; | |
| runUpdateDetailsAlgorithm(this, details); | |
| "> | |
| When the payment sheet is shown, the provided `id` must have no effect on the payment request. | |
| </button></li> | |
| <li><button onclick=" | |
| const details = { | |
| ...neutralDetails, | |
| total: passTotal | |
| }; | |
| runUpdateDetailsAlgorithm(this, details); | |
| "> | |
| When the payment sheet is shown, the total must be CAD$50 with the label "✅ TEST HAS PASSED ✅". | |
| </button></li> | |
| <li><button onclick=" | |
| const details = { | |
| ...neutralDetails, | |
| displayItems: passPaymentItems, | |
| }; | |
| runUpdateDetailsAlgorithm(this, details); | |
| "> | |
| When the payment sheet is shown, there must be a one display item with a value of CAD$50 with the label "✅ TEST HAS PASSED ✅". | |
| </button> | |
| </li> | |
| <li><button onclick=" | |
| const auItem = { | |
| ...passPaymentItem, | |
| amount: { value: '40', currency: 'AUD'}, | |
| pending: true | |
| } | |
| const details = { | |
| ...neutralDetails, | |
| displayItems: passPaymentItems.concat(auItem), | |
| }; | |
| runUpdateDetailsAlgorithm(this, details); | |
| "> | |
| When the payment sheet is shown, there must be | |
| two display items: One with a value of CAD$50, another with | |
| value AUD$40 that is pending. | |
| </button> | |
| </li> | |
| <li><button onclick=" | |
| const details = { | |
| ...neutralDetails, | |
| shippingOptions: [updatedShippingOption1], | |
| }; | |
| runUpdateDetailsAlgorithm(this, details); | |
| "> | |
| When the payment sheet is shown, there must be a one shipping option | |
| with a value of CAD$50. | |
| </button> | |
| </li> | |
| <li><button onclick=" | |
| const details = { | |
| ...neutralDetails, | |
| shippingOptions: passShippingOptions, | |
| }; | |
| runUpdateDetailsAlgorithm(this, details); | |
| "> | |
| When the payment sheet is shown, there must be | |
| two shipping options: One with a value of CAD$50, another with | |
| value AUD$40 that is selected. | |
| </button> | |
| </li> | |
| <li><button onclick=" | |
| const details = { | |
| ...neutralDetails, | |
| modifiers: passModifiers, | |
| }; | |
| runUpdateDetailsAlgorithm(this, details); | |
| "> | |
| When the payment sheet is shown, the total should be CAD$50. | |
| </button> | |
| </li> | |
| <li> | |
| <button onclick=" | |
| const details = { | |
| ...neutralDetails, | |
| shippingOptions: [], | |
| error: passLabel, | |
| }; | |
| runUpdateDetailsAlgorithm(this, details); | |
| "> | |
| When the payment sheet is shown, the string "✅ TEST HAS PASSED ✅" should be shown | |
| somewhere in the user interface. Alternatively, the payment sheet must indicate to the | |
| end user that it's not possible to ship their order. | |
| </button> | |
| </li> | |
| <li> | |
| <button onclick=" | |
| const details = { | |
| ...neutralDetails, | |
| error: failLabel, | |
| }; | |
| runUpdateDetailsAlgorithm(this, details, {requestShipping: false}); | |
| "> | |
| When the payment sheet is shown, there should not be any errors shown. | |
| </button> | |
| </li> | |
| <li> | |
| <button onclick=" | |
| const initialDetails = {total: passTotal, id: 'this cannot be changed'}; | |
| const updatedDetails = {}; | |
| runUpdateDetailsAlgorithm( | |
| this, updatedDetails, {requestShipping: false}, initialDetails); | |
| "> | |
| Resolving the show promise with empty details will preserve the details from | |
| the constructor. When the payment sheet is shown, the string | |
| "✅ TEST HAS PASSED ✅" should be shown. | |
| </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> |