| <!DOCTYPE html> |
| <meta charset="utf-8"> |
| <title>Tests for PaymentRequest interface</title> |
| <script src="../resources/testharness.js"></script> |
| <script src="../resources/testharnessreport.js"></script> |
| <script> |
| function substitute(originalObject, substituteKeyValuePairs) { |
| for (var key in originalObject) { |
| if (originalObject.hasOwnProperty(key) && substituteKeyValuePairs.hasOwnProperty(key)) { |
| originalObject[key] = substituteKeyValuePairs[key]; |
| } |
| } |
| } |
| |
| function buildItem(optionalSubstituteKeyValuePairs) { |
| var item = { |
| 'id': 'item_id', |
| 'label': 'Item Description', |
| 'amount': { |
| 'currency': 'USD', |
| 'value': '10.00' |
| }, |
| 'selected': false |
| }; |
| |
| if (optionalSubstituteKeyValuePairs) { |
| for (var key in optionalSubstituteKeyValuePairs) { |
| assert_true(item.hasOwnProperty(key) || item['amount'].hasOwnProperty(key), 'Unrecognized substitution key "' + key + '"'); |
| } |
| |
| substitute(item, optionalSubstituteKeyValuePairs); |
| substitute(item['amount'], optionalSubstituteKeyValuePairs); |
| } |
| |
| return item; |
| } |
| |
| function setValue(obj, key, val) { |
| keys = key.split(/\./); |
| key = keys.pop(); |
| keys.forEach((k) => { obj = obj[k]; }); |
| assert_true(obj != undefined); |
| obj[key] = val; |
| } |
| |
| function buildDetails(optionalDetailName, optionalSubstituteKeyValuePairs) { |
| var details = { |
| 'total': buildItem(), |
| 'displayItems': [buildItem()], |
| 'shippingOptions': [buildItem()], |
| 'modifiers': [{ |
| 'supportedMethods': ['foo'], |
| 'total': buildItem(), |
| 'additionalDisplayItems': [buildItem()] |
| }] |
| }; |
| |
| if (optionalDetailName) |
| setValue(details, optionalDetailName, buildItem(optionalSubstituteKeyValuePairs)); |
| |
| return details; |
| } |
| |
| test(function() { |
| new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(), {}); |
| }, 'Creating a PaymentRequest with empty parameters should not throw or crash.'); |
| |
| test(function() { |
| new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(), {}, ''); |
| }, 'Creating a PaymentRequest with extra parameters should not throw or crash.'); |
| |
| test(function() { |
| new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails()); |
| }, 'Creating a PaymentRequest with omitted optional parameters should not throw or crash.'); |
| |
| test(function() { |
| new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(), undefined); |
| }, 'Creating a PaymentRequest with undefined optional parameters should not throw or crash.'); |
| |
| test(function() { |
| new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(), null); |
| }, 'Creating a PaymentRequest with null optional parameters should not throw or crash.'); |
| |
| test(function() { |
| var request = new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails()); |
| assert_readonly(request, 'shippingAddress', 'PaymentRequest should have a readonly shippingAddress property.'); |
| assert_readonly(request, 'shippingOption', 'PaymentRequest should have a readonly shippingOption property.'); |
| }, 'PaymentRequest should have readonly shippingAddress and shippingOption properties.'); |
| |
| test(function() { |
| var request = new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails()); |
| assert_not_equals(request.onshippingaddresschange, undefined, 'PaymentRequest should have onShippingAddressChange event.'); |
| assert_not_equals(request.onshippingoptionchange, undefined, 'PaymentRequest should have onShippingOptionChange event.'); |
| }, 'PaymentRequest should have onShippingAddressChange and onShippingOptionChange events.'); |
| |
| test(function() { |
| var request = new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails()); |
| assert_not_equals(request.abort, undefined, 'PaymentRequest should have abort() method.'); |
| assert_not_equals(request.show, undefined, 'PaymentRequest should have show() method.'); |
| }, 'PaymentRequest should have methods abort() and show().'); |
| |
| test(function() { |
| var request = new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails()); |
| request.show(); |
| request.abort(); |
| }, 'PaymentRequest.abort() and PaymentRequest.show() should take no parameters.'); |
| |
| test(function() { |
| var request = new PaymentRequest([{'supportedMethods': ['foo'], 'data': {'foo': {'gateway': 'bar'}}}], buildDetails(), {'requestShipping': true}); |
| request.show(); |
| request.abort(); |
| }, 'Valid data causes no errors.'); |
| |
| test(function() { |
| var request = new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails('shippingOptions.0', {'id': 'standard'})); |
| assert_equals(null, request.shippingOption); |
| }, 'Shipping option identifier should be null if shipping request is omitted.'); |
| |
| test(function() { |
| var request = new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails('shippingOptions.0', {'id': 'standard'}), {'requestShipping': false}); |
| assert_equals(null, request.shippingOption); |
| }, 'Shipping option identifier should be null if shipping is explicitly not requested.'); |
| |
| test(function() { |
| var request = new PaymentRequest([{'supportedMethods': ['foo']}], {'total': buildItem(), 'displayItems': [buildItem()]}, {'requestShipping': true}); |
| assert_equals(null, request.shippingOption); |
| }, 'Shipping option identifier should be null if no shipping options are provided.'); |
| |
| test(function() { |
| var request = new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails('shippingOptions.0', {'selected': false}), {'requestShipping': true}); |
| assert_equals(null, request.shippingOption); |
| }, 'Shipping option identifier should be null if the single provided option is not selected.'); |
| |
| test(function() { |
| var request = new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails('shippingOptions.0', {'id': 'standard', 'selected': true}), {'requestShipping': true}); |
| assert_equals('standard', request.shippingOption); |
| }, 'Shipping option identifier should default to the single provided option if it is selected.'); |
| |
| test(function() { |
| var shippingOptions = [buildItem({'id': 'standard'}), buildItem({'id': 'express'})]; |
| var request = new PaymentRequest([{'supportedMethods': ['foo']}], {'total': buildItem(), 'displayItems': [buildItem()], 'shippingOptions': shippingOptions}, {'requestShipping': true}); |
| assert_equals(null, request.shippingOption); |
| }, 'Shipping option identifier should be null if multiple unselected shipping options are provided.'); |
| |
| test(function() { |
| var shippingOptions = [buildItem({'id': 'standard', 'selected': true}), buildItem({'id': 'express'})]; |
| var request = new PaymentRequest([{'supportedMethods': ['foo']}], {'total': buildItem(), 'displayItems': [buildItem()], 'shippingOptions': shippingOptions}, {'requestShipping': true}); |
| assert_equals('standard', request.shippingOption); |
| }, 'Shipping option identifier should default to the selected shipping option.'); |
| |
| test(function() { |
| var shippingOptions = [buildItem({'id': 'standard', 'selected': true}), buildItem({'id': 'express', 'selected': true})]; |
| var request = new PaymentRequest([{'supportedMethods': ['foo']}], {'total': buildItem(), 'displayItems': [buildItem()], 'shippingOptions': shippingOptions}, {'requestShipping': true}); |
| assert_equals('express', request.shippingOption); |
| }, 'Shipping option identifier should default to the last selected shipping option, if multiple are selected.'); |
| |
| test(function() { |
| new PaymentRequest([{'supportedMethods': ['foo']}], {'total': buildItem(), 'displayItems': undefined}); |
| }, 'Undefined display items should not throw.'); |
| |
| test(function() { |
| new PaymentRequest([{'supportedMethods': ['foo']}], {'total': buildItem(), 'displayItems': []}); |
| }, 'Empty display items should not throw.'); |
| |
| test(function() { |
| new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails('total', {'value': '0'})); |
| }, 'Non-negative total value should not throw.'); |
| |
| test(function() { |
| assert_throws(new TypeError(), function() { |
| new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails('total', {'value': '-0.01'})); |
| }); |
| }, 'Negative total value should throw a TypeError.'); |
| |
| test(function() { |
| new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails('displayItems.0', {'value': '-0.01'})); |
| }, 'Negative line item value should not throw.'); |
| |
| test(function() { |
| assert_throws(new TypeError(), function() { |
| new PaymentRequest([{'supportedMethods': ['foo']}], {'displayItems': [buildItem()]}); |
| }); |
| }, 'Absence of total should throw TypeError.'); |
| |
| test(function() { |
| new PaymentRequest([{'supportedMethods': ['foo']}], {'total': buildItem(), 'modifiers': undefined}); |
| }, 'Undefined modifiers should not throw.'); |
| |
| test(function() { |
| assert_throws(new TypeError(), function() { |
| new PaymentRequest([{'supportedMethods': ['foo']}], {'total': buildItem(), 'modifiers': []}); |
| }); |
| }, 'Empty modifiers should throw TypeError.'); |
| |
| test(function() { |
| assert_throws(new TypeError(), function() { |
| new PaymentRequest([{'supportedMethods': ['foo']}], {'total': buildItem(), 'modifiers': [{'total': buildItem()}]}); |
| }); |
| }, 'Absence of supportedMethods in modifiers should throw TypeError.'); |
| |
| test(function() { |
| assert_throws(new TypeError(), function() { |
| new PaymentRequest([{'supportedMethods': ['foo']}], {'total': buildItem(), 'modifiers': [{'supportedMethods': []}]}); |
| }); |
| }, 'Empty supportedMethods in modifiers should throw TypeError.'); |
| |
| test(function() { |
| assert_throws(new TypeError(), function() { |
| new PaymentRequest([{'supportedMethods': ['foo']}], {'total': buildItem(), 'modifiers': [{'supportedMethods': undefined}]}); |
| }); |
| }, 'Undefined supportedMethods in modifiers should throw TypeError.'); |
| |
| test(function() { |
| assert_throws(new TypeError(), function() { |
| new PaymentRequest([{'supportedMethods': ['foo']}], {'total': buildItem(), 'modifiers': [{'supportedMethods': null}]}); |
| }); |
| }, 'Null supportedMethods in modifiers should throw TypeError.'); |
| |
| test(function() { |
| new PaymentRequest([{'supportedMethods': ['foo']}], {'total': buildItem(), 'modifiers': [{'supportedMethods': ['foo'], 'total': buildItem({'value': '0.0'})}]}); |
| }, 'Non-negative total value in PaymentDetailsModifier should not throw.'); |
| |
| test(function() { |
| assert_throws(new TypeError(), function() { |
| new PaymentRequest([{'supportedMethods': ['foo']}], {'total': buildItem(), 'modifiers': [{'supportedMethods': ['foo'], 'total': buildItem({'value': '-0.01'})}]}); |
| }); |
| }, 'Negative total value in PaymentDetailsModifier should throw a TypeError.'); |
| |
| promise_test(function(t) { |
| return promise_rejects(t, null, new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails()).abort()); |
| }, 'abort() without show() should reject with error'); |
| |
| generate_tests(assert_throws, [ |
| ['PaymentRequest constructor should throw for incorrect parameter types.', null, function() { |
| new PaymentRequest('', '', '') |
| }], |
| ['PaymentRequest constructor should throw for undefined required parameters.', null, function() { |
| new PaymentRequest(undefined, undefined) |
| }], |
| ['PaymentRequest constructor should throw for null required parameter.', null, function() { |
| new PaymentRequest(null, null) |
| }], |
| ['Empty list of supported payment method identifiers should throw TypeError.', new TypeError(), function() { |
| new PaymentRequest([], buildDetails()) |
| }], |
| ['Empty supported payment method identifiers should throw TypeError.', null, function() { |
| new PaymentRequest([{'supportedMethods': []}], buildDetails()) |
| }], |
| ['Empty details should throw', null, function() { |
| new PaymentRequest([{'supportedMethods': ['foo']}], {}) |
| }], |
| ['Null items should throw', new TypeError(), function() { |
| new PaymentRequest([{'supportedMethods': ['foo']}], {'total': buildItem(), 'displayItems': null}); |
| }], |
| ['Null shipping options should throw', new TypeError(), function() { |
| new PaymentRequest([{'supportedMethods': ['foo']}], {'total': buildItem(), 'displayItems': [buildItem()], 'shippingOptions': null}); |
| }], |
| |
| // Payment method specific data should be a JSON-serializable object. |
| ['Array value for payment method specific data parameter should throw', null, function() { |
| new PaymentRequest([{'supportedMethods': ['foo'], 'data': []}], buildDetails(), {}) |
| }], |
| ['String value for payment method specific data parameter should throw', null, function() { |
| new PaymentRequest([{'supportedMethods': ['foo'], 'data': 'foo'}], buildDetails(), {}) |
| }], |
| ['Numeric value for payment method specific data parameter should throw', null, function() { |
| new PaymentRequest([{'supportedMethods': ['foo'], 'data': 42}], buildDetails(), {}) |
| }], |
| ['Infinite JSON value for one of the payment method specific data pieces should throw', null, function() { |
| var infiniteData = {'foo': {}}; |
| infiniteData.foo = infiniteData; |
| new PaymentRequest([{'supportedMethods': ['foo'], 'data': infiniteData}], buildDetails()) |
| }], |
| ['Null for payment method specific data parameter should throw', null, function() { |
| new PaymentRequest([{'supportedMethods': ['foo'], 'data': null}], buildDetails()) |
| }], |
| ['Empty string for payment method specific data parameter should throw', null, function() { |
| new PaymentRequest([{'supportedMethods': ['foo'], 'data': ''}], buildDetails()) |
| }] |
| ]); |
| |
| var detailNames = ['total', 'displayItems.0', 'shippingOptions.0', 'modifiers.0.total', 'modifiers.0.additionalDisplayItems.0']; |
| for (var i in detailNames) { |
| generate_tests(assert_throws, [ |
| // Invalid currency code formats. |
| ['Invalid currency code US1 should throw', null, function() { |
| new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'currency': 'US1'})) |
| }], |
| ['Invalid currency code US should throw', null, function() { |
| new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'currency': 'US'})) |
| }], |
| ['Invalid currency code USDO should throw', null, function() { |
| new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'currency': 'USDO'})) |
| }], |
| ['Invalid currency code usd should throw', null, function() { |
| new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'currency': 'usd'})) |
| }], |
| ['Empty currency code should throw', null, function() { |
| new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'currency': ''})) |
| }], |
| ['Null currency code should throw', null, function() { |
| new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'currency': null})) |
| }], |
| ['Undefined currency code should throw', null, function() { |
| new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'currency': undefined})) |
| }], |
| |
| // Invalid amount formats. |
| ['Invalid amount "-" should throw', null, function() { |
| new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': '-'})) |
| }], |
| ['Invalid amount "notdigits" should throw', null, function() { |
| new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': 'notdigits'})) |
| }], |
| ['Invalid amount "ALSONOTDIGITS" should throw', null, function() { |
| new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': 'ALSONOTDIGITS'})) |
| }], |
| ['Invalid amount "10." should throw', null, function() { |
| new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': '10.'})) |
| }], |
| ['Invalid amount ".99" should throw', null, function() { |
| new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': '.99'})) |
| }], |
| ['Invalid amount "-10." should throw', null, function() { |
| new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': '-10.'})) |
| }], |
| ['Invalid amount "-.99" should throw', null, function() { |
| new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': '-.99'})) |
| }], |
| ['Invalid amount "10-" should throw', null, function() { |
| new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': '10-'})) |
| }], |
| ['Invalid amount "1-0" should throw', null, function() { |
| new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': '1-0'})) |
| }], |
| ['Invalid amount "1.0.0" should throw', null, function() { |
| new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': '1.0.0'})) |
| }], |
| ['Invalid amount "1/3" should throw', null, function() { |
| new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': '1/3'})) |
| }], |
| ['Empty amount should throw', null, function() { |
| new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': ''})) |
| }], |
| ['Null amount should throw', null, function() { |
| new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': null})) |
| }], |
| ['Undefined amount should throw', null, function() { |
| new PaymentRequest([{'supportedMethods': ['foo']}], buildDetails(detailNames[i], {'value': undefined})) |
| }], |
| ]); |
| } |
| </script> |