| <!DOCTYPE html> |
| <meta charset="utf-8"> |
| <title>Test currency code usage in PaymentRequest Constructor</title> |
| <link rel="help" href="https://w3c.github.io/browser-payment-api/#constructor"> |
| <script src="/resources/testharness.js"></script> |
| <script src="/resources/testharnessreport.js"></script> |
| <script> |
| const defaultMethods = [ |
| Object.freeze({ |
| supportedMethods: "https://wpt.fyi", |
| }), |
| ]; |
| const defaultAmount = Object.freeze({ |
| currency: "USD", |
| value: "1.00", |
| }); |
| const defaultTotal = Object.freeze({ |
| label: "Total", |
| amount: defaultAmount, |
| }); |
| |
| const defaultDetails = Object.freeze({ |
| total: Object.freeze({ |
| label: "", |
| amount: defaultAmount, |
| }), |
| }); |
| |
| // The following are the same set of valid/invalid codes that are used in |
| // the ECMAScript Internationalization API Specification (ECMA-402) test suite. |
| const wellFormedCurrencyCodes = [ |
| "BOB", |
| "EUR", |
| "usd", // currency codes are case-insensitive |
| "XdR", |
| "xTs", |
| ]; |
| |
| const invalidCurrencyCodes = [ |
| "", |
| "€", |
| "$", |
| "SFr.", |
| "DM", |
| "KR₩", |
| "702", |
| "ßP", |
| "ınr", |
| ]; |
| |
| const RANGE_ERROR = new RangeError(); |
| |
| const invalidAmount = Object.freeze({ |
| currency: "¡INVALID!", |
| value: "1.00", |
| }); |
| |
| const invalidTotal = { |
| total: { |
| label: "Invalid total", |
| amount: invalidAmount, |
| }, |
| }; |
| |
| // Ensure we don't get false positives |
| function smokeTest() { |
| new PaymentRequest(defaultMethods, invalidTotal); |
| } |
| |
| // Process the total: |
| test(() => { |
| assert_throws(RANGE_ERROR, smokeTest, "Expected smoke test to throw."); |
| for (const validCurrency of wellFormedCurrencyCodes) { |
| const amount = { |
| currency: validCurrency, |
| value: "1.00", |
| }; |
| const total = { |
| label: "Total", |
| amount, |
| }; |
| const details = { |
| total, |
| }; |
| try { |
| new PaymentRequest(defaultMethods, details); |
| } catch (err) { |
| assert_unreached( |
| `Unexpected exception for details.total.amount "${validCurrency}": ${err.message}` |
| ); |
| } |
| } |
| }, "Check and canonicalize valid details.total.amount"); |
| |
| test(() => { |
| assert_throws(RANGE_ERROR, smokeTest, "Expected smoke test to throw."); |
| for (const invalidCurrency of invalidCurrencyCodes) { |
| const amount = { |
| currency: invalidCurrency, |
| value: "1.00", |
| }; |
| const total = { |
| label: "Total", |
| amount, |
| }; |
| const details = { |
| total, |
| }; |
| assert_throws( |
| RANGE_ERROR, |
| () => { |
| new PaymentRequest(defaultMethods, details); |
| }, |
| `Expected RangeError for details.total.amount given ("${invalidCurrency}").` |
| ); |
| } |
| }, "Check and canonicalize invalid details.total.amount and rethrow any exceptions."); |
| |
| // If the displayItems member of details is present, then for each item in details.displayItems: |
| test(() => { |
| assert_throws(RANGE_ERROR, smokeTest, "Expected smoke test to throw."); |
| const displayItems = []; |
| for (const validCurrency of wellFormedCurrencyCodes) { |
| const amount = { |
| currency: validCurrency, |
| value: "123", |
| }; |
| const displayItem = { |
| amount, |
| label: "valid currency", |
| }; |
| const details = { |
| total: defaultTotal, |
| displayItems: [displayItem], |
| }; |
| try { |
| new PaymentRequest(defaultMethods, details); |
| } catch (err) { |
| assert_unreached( |
| `Unexpected error with displayItem that had a valid currency "${validCurrency}": ${err.message}` |
| ); |
| } |
| displayItems.push(displayItem); |
| } |
| // Let's make sure it doesn't throw given a list of valid displayItems |
| try { |
| const details = Object.assign({}, defaultDetails, { displayItems }); |
| new PaymentRequest(defaultMethods, details); |
| } catch (err) { |
| assert_unreached( |
| `Unexpected error with multiple valid displayItems: ${err.message}` |
| ); |
| } |
| }, "Check and canonicalize valid details.displayItems amount"); |
| |
| test(() => { |
| assert_throws(RANGE_ERROR, smokeTest, "Expected smoke test to throw."); |
| for (const invalidCurrency of invalidCurrencyCodes) { |
| const amount = { |
| currency: invalidCurrency, |
| value: "123", |
| }; |
| const displayItem = { |
| amount, |
| label: "invalid currency", |
| }; |
| const details = { |
| total: defaultTotal, |
| displayItems: [displayItem], |
| }; |
| assert_throws( |
| RANGE_ERROR, |
| () => { |
| new PaymentRequest(defaultMethods, details); |
| }, |
| `Expected RangeError with invalid displayItem currency "${invalidCurrency}".` |
| ); |
| } |
| }, "Check and canonicalize invalid details.displayItems amount and rethrow RangeError."); |
| |
| // Process shipping options: |
| test(() => { |
| assert_throws(RANGE_ERROR, smokeTest, "Expected smoke test to throw."); |
| const shippingOptions = []; |
| for (const validCurrency of wellFormedCurrencyCodes) { |
| const shippingOption = { |
| id: `test` + Math.random(), |
| label: "shipping option", |
| amount: { currency: validCurrency, value: "5.00" }, |
| selected: !shippingOptions.length, |
| }; |
| const details = { |
| total: defaultTotal, |
| shippingOptions: [shippingOption], |
| }; |
| try { |
| new PaymentRequest(defaultMethods, details, { requestShipping: true }); |
| } catch (err) { |
| assert_unreached( |
| `Unexpected exception with valid shippingOption currency code "${validCurrency}": ${err.message}.` |
| ); |
| } |
| shippingOptions.push(shippingOption); |
| } |
| try { |
| const details = Object.assign({}, defaultDetails, { shippingOptions }); |
| new PaymentRequest(defaultMethods, details, { requestShipping: true }); |
| } catch (err) { |
| assert_unreached( |
| `Unexpected error with multiple valid shppingOptions: ${err.message}.` |
| ); |
| } |
| }, "Check and canonicalize valid details.shippingOptions amount."); |
| |
| test(() => { |
| assert_throws(RANGE_ERROR, smokeTest, "Expected smoke test to throw."); |
| for (const invalidCurrency of invalidCurrencyCodes) { |
| const shippingOption = { |
| id: "test", |
| label: "shipping option", |
| amount: { currency: invalidCurrency, value: "5.00" }, |
| selected: true, |
| }; |
| const details = { |
| total: defaultTotal, |
| shippingOptions: [shippingOption], |
| }; |
| assert_throws( |
| RANGE_ERROR, |
| () => { |
| new PaymentRequest(defaultMethods, details, { requestShipping: true }); |
| }, |
| `Expected RangeError with invalid shippingOption currency code "${invalidCurrency}".` |
| ); |
| } |
| }, "Check and canonicalize invalid details.shippingOptions amount and rethrow RangeError."); |
| |
| // Process payment details modifiers: |
| test(() => { |
| assert_throws(RANGE_ERROR, smokeTest, "Expected smoke test to throw."); |
| for (const validCurrency of wellFormedCurrencyCodes) { |
| const modifier = { |
| supportedMethods: "https://wpt.fyi", |
| total: { |
| label: "Total due", |
| amount: { currency: validCurrency, value: "68.00" }, |
| }, |
| }; |
| const details = { |
| total: defaultTotal, |
| modifiers: [modifier], |
| }; |
| try { |
| new PaymentRequest(defaultMethods, details); |
| } catch (err) { |
| assert_unreached( |
| `Unexpected error with valid modifier currency code "${validCurrency}": ${err.message}` |
| ); |
| } |
| } |
| }, "Check and canonicalize valid modifiers[n].total amount."); |
| |
| test(() => { |
| assert_throws(RANGE_ERROR, smokeTest, "Expected smoke test to throw."); |
| for (const invalidCurrency of invalidCurrencyCodes) { |
| const modifier = { |
| supportedMethods: "https://wpt.fyi", |
| total: { |
| label: "Total due", |
| amount: { currency: invalidCurrency, value: "68.00" }, |
| }, |
| }; |
| const details = { |
| total: defaultTotal, |
| modifiers: [modifier], |
| }; |
| assert_throws( |
| RANGE_ERROR, |
| () => { |
| new PaymentRequest(defaultMethods, details); |
| }, |
| `Expected RangeError with invalid modifier currency code "${invalidCurrency}".` |
| ); |
| } |
| }, "Check and canonicalize invalid modifiers[n].total amount and rethrow RangeError."); |
| |
| // Process payment details modifiers: |
| test(() => { |
| assert_throws(RANGE_ERROR, smokeTest, "Expected smoke test to throw."); |
| for (const validCurrency of wellFormedCurrencyCodes) { |
| const additionalItem = { |
| label: "additionalItem", |
| amount: { currency: validCurrency, value: "3.00" }, |
| }; |
| const modifier = { |
| supportedMethods: "https://wpt.fyi", |
| total: defaultTotal, |
| additionalDisplayItems: [additionalItem], |
| }; |
| const details = { |
| total: defaultTotal, |
| modifiers: [modifier], |
| }; |
| try { |
| new PaymentRequest(defaultMethods, details); |
| } catch (err) { |
| assert_unreached( |
| `Unexpected error with valid additionalDisplayItems[n] currency code "${validCurrency}": ${err.message}` |
| ); |
| } |
| } |
| }, "Check and canonicalize valid modifiers[n].additionaDisplayItem amount."); |
| |
| test(() => { |
| assert_throws(RANGE_ERROR, smokeTest, "Expected smoke test to throw."); |
| for (const invalidCurrency of invalidCurrencyCodes) { |
| const additionalItem = { |
| label: "additionalItem", |
| amount: { currency: invalidCurrency, value: "3.00" }, |
| }; |
| const modifier = { |
| supportedMethods: "https://wpt.fyi", |
| total: defaultTotal, |
| additionalDisplayItems: [additionalItem], |
| }; |
| const details = { |
| total: defaultTotal, |
| modifiers: [modifier], |
| }; |
| assert_throws( |
| RANGE_ERROR, |
| () => { |
| new PaymentRequest(defaultMethods, details); |
| }, |
| `Expected RangeError with invalid additionalDisplayItems[n] currency code "${invalidCurrency}".` |
| ); |
| } |
| }, "Check and canonicalize invalid modifiers[n].additionaDisplayItem amount and rethrow RangeError."); |
| </script> |