| <!DOCTYPE html> |
| <meta charset="utf-8" /> |
| <title>Test for PaymentRequest.show(optional detailsPromise) 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 src="/resources/testdriver.js"></script> |
| <script src="/resources/testdriver-vendor.js"></script> |
| <script> |
| // See function testBadUpdate() for test details! |
| setup({ |
| allow_uncaught_exception: true, |
| }); |
| |
| // == TEST DATA === |
| // PaymentMethod |
| const validMethod = Object.freeze({ |
| supportedMethods: "valid-but-wont-ever-match", |
| }); |
| |
| const validMethodBasicCard = Object.freeze({ |
| supportedMethods: "basic-card", |
| }); |
| |
| const validMethodApplePay = 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, |
| validMethodApplePay, |
| ]); |
| |
| // 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, |
| }); |
| // == END OF TEST DATA === |
| /* |
| These test work by creating a "valid" payment request and then |
| performing a bad update via `show(detailsPromise)`. |
| The `badDetails` cause detailsPromise to reject with `expectedError`. |
| */ |
| function testBadUpdate(testAssertion, badDetails, expectedError) { |
| promise_test(async (t) => { |
| const request = new PaymentRequest( |
| validMethods, |
| validDetails, |
| validOptions |
| ); |
| await test_driver.bless("Payment request"); |
| const detailsPromise = Promise.resolve(badDetails); |
| const acceptPromise = request.show(detailsPromise); |
| const test_func = |
| typeof expectedError == "function" |
| ? promise_rejects_js |
| : promise_rejects_dom; |
| await test_func( |
| t, |
| expectedError, |
| acceptPromise, |
| "badDetails must cause acceptPromise to reject with expectedError" |
| ); |
| }, testAssertion); |
| } |
| |
| const rejectedPromise = Promise.reject(new SyntaxError("test")); |
| testBadUpdate( |
| "Rejection of detailsPromise must abort the update with an 'AbortError' DOMException.", |
| rejectedPromise, |
| "AbortError" |
| ); |
| |
| testBadUpdate( |
| "Total in the update is a string, so converting to IDL must abort the update with a TypeError.", |
| { total: `this will cause a TypeError!` }, |
| TypeError |
| ); |
| |
| testBadUpdate( |
| "Total is recursive, so converting to IDL must abort the update with a TypeError.", |
| { total: recursiveData }, |
| TypeError |
| ); |
| |
| testBadUpdate( |
| "Updating with a negative total results in a TypeError.", |
| invalidDetailsNegativeTotal, |
| TypeError |
| ); |
| |
| testBadUpdate( |
| "Updating with a displayItem with an invalid currency results in RangeError.", |
| { ...validDetails, displayItems: invalidPaymentItems }, |
| RangeError |
| ); |
| |
| testBadUpdate( |
| "Updating with duplicate shippingOptions (same IDs) results in a TypeError.", |
| { |
| ...validDetails, |
| shippingOptions: [validShippingOption, validShippingOption], |
| }, |
| TypeError |
| ); |
| |
| testBadUpdate( |
| "Updating with a shippingOption with an invalid currency value results in a RangError.", |
| { ...validDetails, shippingOptions: invalidShippingOptions }, |
| RangeError |
| ); |
| |
| testBadUpdate( |
| "Must throw a RangeError when a modifier's total item has an invalid currency.", |
| { ...validDetails, modifiers: [modifierWithInvalidTotal, validModifier] }, |
| RangeError |
| ); |
| |
| testBadUpdate( |
| "Must throw a RangeError when a modifier display item has an invalid currency.", |
| { |
| ...validDetails, |
| modifiers: [modifierWithInvalidDisplayItems, validModifier], |
| }, |
| RangeError |
| ); |
| testBadUpdate( |
| "Must throw as Modifier has a recursive dictionary.", |
| { ...validDetails, modifiers: [modifierWithRecursiveData, validModifier] }, |
| TypeError |
| ); |
| </script> |